Compare commits

...

582 Commits

Author SHA1 Message Date
AkaraChen
5ad148b8f9 style: refactor context 2024-11-15 14:26:46 +08:00
Joel
6b759795d5 feat: can install github 2024-11-15 13:09:29 +08:00
Joel
bba80f465b just add 2024-11-15 13:09:28 +08:00
Yi
735e47f5e5 chore: update the styling in the "members setting" 2024-11-15 11:29:48 +08:00
twwu
d354c69493 chore: update translations to include 'Marketplace' terminology in Chinese localization 2024-11-15 11:05:20 +08:00
JzoNg
8f14881aff app parameters 2024-11-15 10:43:21 +08:00
JzoNg
e53c4fc0ad empty inputs form of app selector 2024-11-15 10:43:21 +08:00
JzoNg
f9f2e68bd8 app selector in form 2024-11-15 10:43:21 +08:00
JzoNg
7b4d67d72f app list filter 2024-11-15 10:43:21 +08:00
JzoNg
7446244147 app picker 2024-11-15 10:43:21 +08:00
JzoNg
c723bd2c96 app selector trigger 2024-11-15 10:43:21 +08:00
Joel
73ce8a17a5 feat: add loading 2024-11-15 10:39:57 +08:00
Joel
6f5e010db5 chore: handle uploaded selected 2024-11-14 18:31:22 +08:00
Yi
495d86fd96 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-14 18:28:18 +08:00
Yi
42ba4e4f0e chore: update the plugins tab button 2024-11-14 18:26:16 +08:00
StyleZhang
6af51701de fix: card link 2024-11-14 18:18:10 +08:00
Joel
76104d811c feat: can show install plugins 2024-11-14 16:54:36 +08:00
StyleZhang
1877433f20 fix: marketplace 2024-11-14 16:37:53 +08:00
Yi
a403fb565d chore: update the plan tags 2024-11-14 16:21:28 +08:00
twwu
f58b88f319 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-14 15:47:27 +08:00
twwu
cd2860deb4 feat: add i18n support for plugin installation and empty states 2024-11-14 15:47:22 +08:00
AkaraChen
070968a048 style: add lint rule for tailwind 2024-11-14 15:39:21 +08:00
StyleZhang
ceb18d160f fix: marketplace i18n 2024-11-14 14:56:15 +08:00
StyleZhang
6a63a03cb2 feat: tool list use query 2024-11-14 14:48:13 +08:00
twwu
a0a62db6ad refactor: Split linear-gradient and color 2024-11-14 14:36:30 +08:00
StyleZhang
253abaf1a3 fix: marketplace empty page 2024-11-14 14:27:34 +08:00
AkaraChen
44cc6157f1 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-14 11:35:53 +08:00
Yi
028fc00be6 chore: update i18n & setting window 2024-11-14 11:19:39 +08:00
AkaraChen
1aed0fe5d6 chore: use mitt hook 2024-11-14 11:04:41 +08:00
JzoNg
300cd675c6 update tool list after tool selector 2024-11-14 00:04:06 +08:00
JzoNg
ff1d42bd66 add tool selector in endpoint modal 2024-11-14 00:02:04 +08:00
JzoNg
194a99220b authorization of tool selector 2024-11-14 00:02:04 +08:00
JzoNg
926f85ce4f tool selector trigger 2024-11-14 00:02:04 +08:00
Yi
6c6e1e90cd Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-13 18:41:27 +08:00
twwu
2fbc0c2261 revert: revert category label handling in plugin card component 2024-11-13 18:40:23 +08:00
Yi
bac1e99557 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-13 18:40:20 +08:00
Yi
93e3077f77 chore: update the esc button and the upgrade button 2024-11-13 18:40:11 +08:00
twwu
fa6858090b refactor: remove version prop from plugin item components and update version comparison logic 2024-11-13 18:34:04 +08:00
twwu
61eb655823 feat: update plugin category labels and improve internationalization support 2024-11-13 18:30:38 +08:00
twwu
6298332950 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-13 16:55:49 +08:00
twwu
a1719c49b7 feat: add internationalization support for plugin categories and update translations 2024-11-13 16:55:43 +08:00
Yi
b10a1cd325 chore: update the theme selector setting in globals.css 2024-11-13 16:43:00 +08:00
StyleZhang
aa88028564 fix: marketplace list 2024-11-13 16:28:38 +08:00
Joel
3e314843db chore: add missing file 2024-11-13 16:23:33 +08:00
Joel
0d607a8c90 feat: add update workflow to update use query 2024-11-13 16:23:31 +08:00
StyleZhang
577a948f42 feat: dsl check plugin 2024-11-13 15:48:25 +08:00
Joel
edbfe27eb1 chore: add invalid all built in tools 2024-11-13 15:17:22 +08:00
Joel
5c98d80fdf chore: more filter text content 2024-11-13 15:12:58 +08:00
Joel
89b470d0d5 fix: toggle tool 2024-11-13 15:04:23 +08:00
Joel
19dc983d30 feat: support toggle set tool when the texts changes 2024-11-13 14:54:37 +08:00
twwu
e842a46fe2 fix: resolve issue with dark mode 2024-11-13 14:43:37 +08:00
Joel
1573f6f6aa feat: add tag and q filter 2024-11-13 14:08:16 +08:00
AkaraChen
910d5df513 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-13 13:33:47 +08:00
twwu
fa01360498 fix: Fix theme initialization issue 2024-11-13 13:11:47 +08:00
AkaraChen
1fe5be532d fix: new workflow init draft failed 2024-11-13 12:59:52 +08:00
Joel
d67eb907dd fix: show index letter problem 2024-11-13 11:56:33 +08:00
Joel
83dae7e5bc fix: can not select action in workflow and tools 2024-11-13 11:38:44 +08:00
StyleZhang
c6d1b7869d fix: plugin task 2024-11-13 11:33:58 +08:00
Yi
601d267b7a Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-13 10:39:07 +08:00
Yi
327940a120 chore: update the update plugin from GitHub 2024-11-13 10:38:56 +08:00
StyleZhang
582c7ce348 fix: plugin task 2024-11-12 18:28:34 +08:00
StyleZhang
13d3f67746 feat: plugin task use query 2024-11-12 17:58:32 +08:00
Joel
9c6aafd415 feat: install bundle ui 2024-11-12 17:33:10 +08:00
nite-knite
3716ea46b5 chore: bump elliptic from 6.5.7 to 6.6.0 2024-11-12 17:19:02 +08:00
JzoNg
3c89b8a698 confirm model selector schema in agent and workflow 2024-11-12 16:57:22 +08:00
JzoNg
b188800f16 model selector in endpoint modal 2024-11-12 16:57:22 +08:00
JzoNg
75a037bc2a update style of model & parameter selector 2024-11-12 16:57:22 +08:00
JzoNg
5efcdd6fa7 model parameters 2024-11-12 16:57:22 +08:00
JzoNg
06c4627abb tool selecting in configure 2024-11-12 16:57:22 +08:00
JzoNg
f5267d317e fix quota of model provider 2024-11-12 16:57:22 +08:00
twwu
2573950f88 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-12 16:48:28 +08:00
twwu
2ba38c6c45 feat: add marketplace-divider-bg color variable for dark and light themes 2024-11-12 16:48:24 +08:00
Joel
07edda8a85 feat: add new marketplace env 2024-11-12 15:56:03 +08:00
twwu
7791d290c7 refactor: update AudioPlayer styles with CSS variables and improve VideoGallery rendering 2024-11-12 15:49:00 +08:00
Joel
8203b23df2 feat: install bundle struct 2024-11-12 15:48:00 +08:00
Joel
d4c9c76454 chore: mask the debug key 2024-11-12 14:31:15 +08:00
AkaraChen
a059660ed8 fix: sse post no token 2024-11-12 14:24:18 +08:00
Yi
20357beda4 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-12 13:32:26 +08:00
Joel
7e39565fd2 feat: handle on update show update modal 2024-11-12 11:48:55 +08:00
StyleZhang
27f794e197 feat: plugin task 2024-11-11 18:17:58 +08:00
Yi
a8e8e36756 chore: update the upgrade button 2024-11-11 18:00:44 +08:00
Yi
dbc10425c8 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-11 17:21:37 +08:00
Yi
810443c511 chore: update the upgrade button and add premium badge component 2024-11-11 17:21:25 +08:00
Joel
f47b5ce63a chore: install plugin by local use use query 2024-11-11 14:58:17 +08:00
StyleZhang
822c18cb76 fix: credentials: 2024-11-11 12:27:58 +08:00
StyleZhang
66b08e653e fix: credentials: 2024-11-11 12:27:13 +08:00
JzoNg
5e81150b22 useQuery for endpoints 2024-11-09 14:44:48 +08:00
JzoNg
1e62768eed useQuery in action list 2024-11-09 12:51:10 +08:00
JzoNg
59a9235041 useQuery for model list 2024-11-09 12:12:10 +08:00
JzoNg
f2bf2e4470 fix style of provider added card 2024-11-08 21:32:46 +08:00
Joel
c77b38b97d chore: install from marketplace 2024-11-08 18:29:54 +08:00
StyleZhang
33349191e9 marketplace usemutation 2024-11-08 18:21:58 +08:00
AkaraChen
d4f7ebfd2e feat: refactor http client 2024-11-08 17:21:55 +08:00
JzoNg
ebdf72fffc check update 2024-11-08 17:01:49 +08:00
JzoNg
1f1c61541e install from settings 2024-11-08 16:33:00 +08:00
JzoNg
f70c23dd7a endpoints api 2024-11-08 16:19:00 +08:00
JzoNg
f498686c3a model list style fix 2024-11-08 16:19:00 +08:00
StyleZhang
d13169934d fix: marketplace i18n 2024-11-08 16:14:29 +08:00
Joel
324437b3f1 feat: mutation permersions 2024-11-08 16:12:04 +08:00
twwu
c6a6c53084 chore: update theme var define 2024-11-08 15:26:59 +08:00
Joel
edc2fe050a chore: debug info use query 2024-11-08 15:10:06 +08:00
Joel
6fcebf3ecd chore: remove log 2024-11-08 14:26:52 +08:00
Joel
b754bf80ae fix: custom tools not show 2024-11-08 14:24:28 +08:00
Joel
a9de7f24a2 merge main 2024-11-08 13:55:39 +08:00
twwu
6759c6d5e6 Revert "feat: add gray label color variables for dark and light themes"
This reverts commit a75cef2c3b.
2024-11-08 13:42:38 +08:00
JzoNg
920d6d6882 fix credentials of action list 2024-11-08 12:32:02 +08:00
JzoNg
2511968cb4 fix action list 2024-11-08 12:32:02 +08:00
JzoNg
f684e1c12e provider compatible in logs 2024-11-08 12:32:02 +08:00
JzoNg
be75a1e432 provider compatible in moderation 2024-11-08 12:32:02 +08:00
JzoNg
5a679ed396 provider compatible in model_config 2024-11-08 12:32:02 +08:00
JzoNg
0cfd676fd6 provider compatible 2024-11-08 12:32:02 +08:00
twwu
d997499ecf Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-08 11:33:42 +08:00
twwu
4d3ffbb6f0 fix: update repository URL format in plugin action component 2024-11-08 11:33:35 +08:00
twwu
a710858d09 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-08 11:32:34 +08:00
twwu
a75cef2c3b feat: add gray label color variables for dark and light themes 2024-11-08 11:31:48 +08:00
Yi
392db19ea2 chore: update the update plugin steps 2024-11-08 11:08:40 +08:00
Yi
7cb6039833 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 18:22:08 +08:00
Yi
e041a9e418 chore: upgrade button styling 2024-11-07 18:21:32 +08:00
Joel
281c6dc337 merge 2024-11-07 17:44:54 +08:00
-LAN-
7d7ade26ce fix(remote-files): fallback to get when remote server not support head method (#10370) 2024-11-07 17:39:52 +08:00
-LAN-
6aa2af215b refactor(iteration): introduce specific exceptions for iteration errors (#10366) 2024-11-07 17:39:52 +08:00
-LAN-
598d307afd refactor(knowledge-retrieval): improve error handling with custom exceptions (#10385) 2024-11-07 17:39:52 +08:00
-LAN-
39fdcfd7e9 refactor(tool-node): introduce specific exceptions for tool node errors (#10357) 2024-11-07 17:39:51 +08:00
-LAN-
47f638e5aa refactor(question_classifier): improve error handling with custom exceptions (#10365) 2024-11-07 17:39:51 +08:00
luckylhb90
03b57d1f0a fixed: web api remote urls error (#10383)
Co-authored-by: hobo.l <hobo.l@binance.com>
2024-11-07 17:39:51 +08:00
powerfool
99c84c423e Adjusted docker manifests and environment variables for OceanBase vector database (#10395) 2024-11-07 17:39:51 +08:00
omr
cc2cc56f25 fix typo: mMaximum -> Maximum (#10389) 2024-11-07 17:39:50 +08:00
非法操作
393885ee16 fix: remove duplicated category “recommended” (#10375) 2024-11-07 17:39:50 +08:00
Matsuda
9143d460fa fix(model_runtime): remove vision from features for Claude 3.5 Haiku (#10360) 2024-11-07 17:39:49 +08:00
Infinitnet
c0ff0cf7cf fix: remove unsupported vision in OpenRouter Haiku 3.5 (#10364) 2024-11-07 17:39:49 +08:00
Bowen Liang
9c90d98027 chore(ci): bring back poetry cache to speed up CI jobs (#10347) 2024-11-07 17:39:48 +08:00
Bowen Liang
0d74466f45 chore: lazy import sagemaker (#10342) 2024-11-07 17:39:48 +08:00
comfuture
d2e293b9be chore: update translation for 'account' from '계좌' to '계정' (#10350) 2024-11-07 17:39:48 +08:00
-LAN-
8fae321b6a chore(ci): separate vector store tests into new workflow (#10354) 2024-11-07 17:39:47 +08:00
-LAN-
a2b42c9431 fix(api): remove fixed source attribute from FileApi (#10353) 2024-11-07 17:39:47 +08:00
Nam Vu
0a4b256b5a feat: support png, gif, webp (#7947)
Co-authored-by: xuanson9699 <84961581+xuanson9699@users.noreply.github.com>
2024-11-07 17:39:47 +08:00
Chenhe Gu
9f7124a79d Update README.md (#10332) 2024-11-07 17:39:46 +08:00
方程
7a217534d1 Gitee AI tools (#10314) 2024-11-07 17:39:46 +08:00
Summer-Gu
a9ed0f0b42 feat: The SSRF request timeout configuration item is added (#10292) 2024-11-07 17:39:46 +08:00
Infinitnet
545d2b2622 feat: add support for anthropic/claude-3-5-haiku through OpenRouter (#10331) 2024-11-07 17:39:45 +08:00
Benjamin
f114da4e81 feat(vannaai): add base_url configuration (#10294) 2024-11-07 17:39:45 +08:00
-LAN-
f4e3e3fc19 docs: remove the TOC part (#10324) 2024-11-07 17:39:45 +08:00
非法操作
1277941821 fix: special prompt not work for comfyUI tool (#10307) 2024-11-07 17:39:45 +08:00
-LAN-
f500e6cf5b chore: update version to 0.11.0 across all relevant files (#10278) 2024-11-07 17:39:44 +08:00
Novice
a3b71830d0 fix: iteration none output error (#10295) 2024-11-07 17:39:44 +08:00
-LAN-
13b7e18a50 fix(http_request): improve parameter initialization and reorganize tests (#10297) 2024-11-07 17:39:44 +08:00
Matsuda
5f4bb12a1a fix typo: writeOpner to writeOpener (#10290) 2024-11-07 17:39:43 +08:00
pinsily
781e8e1a4a fix: handle KeyError when accessing rules in CleanProcessor.clean (#10258) 2024-11-07 17:39:43 +08:00
eux
c721617e19 fix: borken faq url in CONTRIBUTING.md (#10275) 2024-11-07 17:39:43 +08:00
非法操作
6b51e81de1 feat: add xAI model provider (#10272) 2024-11-07 17:39:43 +08:00
Matsuda
736719745c feat(model_runtime): add new model 'claude-3-5-haiku-20241022' (#10285) 2024-11-07 17:39:43 +08:00
Matsuda
e0e4a6f819 fix(model_runtime): fix wrong max_tokens for Claude 3.5 Haiku on Amazon Bedrock (#10286) 2024-11-07 17:39:42 +08:00
-LAN-
6ab6b9cc40 feat(model): add validation for custom disclaimer length (#10287) 2024-11-07 17:39:42 +08:00
-LAN-
52eb18937e fix(node): correct file property name in function switch (#10284) 2024-11-07 17:39:42 +08:00
NFish
aab1ab692a refactor the logic of refreshing access_token (#10068) 2024-11-07 17:39:40 +08:00
github-actions[bot]
3e7f38d904 chore: translate i18n files (#10273)
Co-authored-by: laipz8200 <16485841+laipz8200@users.noreply.github.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
2024-11-07 17:39:15 +08:00
Benjamin
94c5e36334 Updates: Add mplfonts library for customizing matplotlib fonts and Va… (#9903) 2024-11-07 17:39:14 +08:00
Novice
baaa3ae02c feat: Iteration node support parallel mode (#9493) 2024-11-07 17:39:09 +08:00
GeorgeCaoJ
623b27583b fix(workflow): handle else condition branch addition error in if-else node (#10257) 2024-11-07 17:38:39 +08:00
-LAN-
93e9aeb4e9 feat(document_extractor): support tool file in document extractor (#10217) 2024-11-07 17:38:39 +08:00
Matsuda
391ad7734e feat: support Claude 3.5 Haiku on Amazon Bedrock (#10265) 2024-11-07 17:38:38 +08:00
-LAN-
c5422af400 refactor(parameter_extractor): implement custom error classes (#10260) 2024-11-07 17:38:37 +08:00
guogeer
65a04ee0be fix: buitin tool aippt (#10234)
Co-authored-by: jinqi.guo <jinqi.guo@ubtrobot.com>
2024-11-07 17:38:37 +08:00
-LAN-
84c35aef6c fix(validation): allow to use 0 in the inputs form (#10255) 2024-11-07 17:38:37 +08:00
-LAN-
c2b4845719 chore(Dockerfile): upgrade zlib arm64 (#10244) 2024-11-07 17:38:37 +08:00
方程
cd0f10567f Using a dedicated interface to obtain the token credential for the gitee.ai provider (#10243) 2024-11-07 17:38:36 +08:00
-LAN-
454b755c6b feat(workflow): add configurable workflow file upload limit (#10176)
Co-authored-by: JzoNg <jzongcode@gmail.com>
2024-11-07 17:38:35 +08:00
shisaru292
352c1fc370 fix: missing working directory parameter in script (#10226) 2024-11-07 17:38:35 +08:00
-LAN-
181eb6038f refactor(list_operator): replace ValueError with InvalidKeyError (#10222) 2024-11-07 17:38:34 +08:00
-LAN-
c32cbeb29a refactor(workflow): introduce specific error handling for LLM nodes (#10221) 2024-11-07 17:38:34 +08:00
-LAN-
62f8c875c8 refactor(http_request): add custom exception handling for HTTP request nodes (#10219) 2024-11-07 17:38:33 +08:00
-LAN-
baed53bbfa refactor(workflow): introduce specific exceptions for code validation (#10218) 2024-11-07 17:38:32 +08:00
-LAN-
565a0d992a chore(llm_node): remove unnecessary type ignore for context assignment (#10216) 2024-11-07 17:38:32 +08:00
Jyong
e90a06a7b7 fix the ssrf of docx file extractor external images (#10237) 2024-11-07 17:38:31 +08:00
Hanqing Zhao
5a0b22dbd4 Modify translation (#10213) 2024-11-07 17:38:30 +08:00
Jiang
31445c3782 Add Lindorm as a VDB choice (#10202)
Co-authored-by: jiangzhijie <jiangzhijie.jzj@alibaba-inc.com>
2024-11-07 17:38:30 +08:00
crazywoola
8e6f5f4bb0 Fix/10199 application error a client side exception has occurred see the browser console for more information (#10211) 2024-11-07 17:38:29 +08:00
-LAN-
e259b360c2 refactor(validation): improve input validation logic (#10175) 2024-11-07 17:38:29 +08:00
-LAN-
762dec2dc4 chore(list_operator): refine exception handling for error specificity (#10206) 2024-11-07 17:38:28 +08:00
-LAN-
ada7f5c30f fix(document_extractor): update base exception class (#10208) 2024-11-07 17:38:28 +08:00
Kota-Yamaguchi
6b965eaea3 Feat : add LLM model indicator in prompt generator (#10187) 2024-11-07 17:38:27 +08:00
Xiao Ley
ea67bc1166 chore: enable vision support for models in OpenRouter that should have supported vision (#10191) 2024-11-07 17:38:26 +08:00
Kota-Yamaguchi
01e8f6066a chore : code generator preview hint (#10188) 2024-11-07 17:38:26 +08:00
zxhlyh
39effd350e fix: webapp upload file (#10195) 2024-11-07 17:38:25 +08:00
-LAN-
00bfb35759 fix(api): replace current_user with end_user in file upload (#10194) 2024-11-07 17:38:25 +08:00
-LAN-
101d9798f0 feat(document_extractor): integrate unstructured API for PPTX extraction (#10180) 2024-11-07 17:38:24 +08:00
-LAN-
ba48754be6 fix(tools): suppress RuntimeWarnings in podcast audio generator (#10182) 2024-11-07 17:38:24 +08:00
Cling_o3
d963df32b9 [fix] fix the bug that modify document name not effective (#10154) 2024-11-07 17:38:23 +08:00
-LAN-
67ce763377 fix(workflow model): ensure consistent timestamp updating (#10172) 2024-11-07 17:38:23 +08:00
jiangbo721
a32c0ef43c fix: Cannot find declaration to go to CLEAN_DAY_SETTING (#10157)
Co-authored-by: 刘江波 <liujiangbo1@xiaomi.com>
2024-11-07 17:38:22 +08:00
Lawrence Li
6e03c10285 feat: add gpustack model provider (#10158) 2024-11-07 17:38:21 +08:00
-LAN-
8f14c422a7 refactor(tools): Avoid warnings. (#10161) 2024-11-07 17:38:20 +08:00
-LAN-
07787366cd refactor(migration/model): update column types for workflow schema (#10160) 2024-11-07 17:38:20 +08:00
-LAN-
8f2d3b6743 Feat/add-remote-file-upload-api (#9906) 2024-11-07 17:38:19 +08:00
zxhlyh
e7bc863f26 fix: upload remote image preview (#9952) 2024-11-07 17:38:19 +08:00
Jyong
1d411e195a clean un-allowed special charters when doing indexing estimate (#10153) 2024-11-07 17:38:19 +08:00
-LAN-
2a7ae6b0df refactor(service): handle unsupported DSL version with warning (#10151) 2024-11-07 17:38:18 +08:00
larcane97
8f8a3f4318 Add VESSL AI OpenAI API-compatible model provider and LLM model (#9474)
Co-authored-by: moon <moon@vessl.ai>
2024-11-07 17:38:18 +08:00
Kota-Yamaguchi
4b89dba3a5 feat: synchronize input/output variables in the panel with generated code by the code generator (#10150) 2024-11-07 17:38:18 +08:00
Zixuan Cheng
19c0d1fbf8 Refined README for better reading experience. (#10143) 2024-11-07 17:38:17 +08:00
Coal Pigeon
94cd4912e1 add llm: ernie-4.0-turbo-128k of wenxin (#10135)
Co-authored-by: Pigeon姚宏锋 <pigeon.yhf@galaxyoversea.com>
2024-11-07 17:38:17 +08:00
Shili Cao
602f75bb30 fix: avoid unexpected error when create knowledge base with baidu vector database and wenxin embedding model (#10130) 2024-11-07 17:38:15 +08:00
llinvokerl
c2810de952 fix: bar chart issue with duplicate x-axis labels being incorrectly ignored (#10134)
Co-authored-by: liusurong.lsr <liusurong.lsr@alibaba-inc.com>
2024-11-07 17:38:14 +08:00
Jyong
1b645c1cc9 fix issue: query is none when doing retrieval (#10129) 2024-11-07 17:38:14 +08:00
zxhlyh
ae3482e0b4 Fix/rerank validation issue (#10131)
Co-authored-by: Yi <yxiaoisme@gmail.com>
2024-11-07 17:38:14 +08:00
Jyong
76c265f781 Feat/update knowledge api url (#10102)
Co-authored-by: nite-knite <nkCoding@gmail.com>
2024-11-07 17:38:12 +08:00
omr
b1946c60d8 fix: optimize unique document filtering with set (#10082) 2024-11-07 17:38:12 +08:00
-LAN-
c1c13cf828 fix(Dockerfile): conditionally install zlib1g based on architecture (#10118) 2024-11-07 17:38:11 +08:00
Hash Brown
e4a48e28e5 fix: log detail panel not showing any message when total count greate… (#10119) 2024-11-07 17:38:11 +08:00
Jyong
67efcbd6bb fix issue: update document segment setting failed (#10107) 2024-11-07 17:38:11 +08:00
Nam Vu
7466061e5a fix: Version '1:1.3.dfsg+really1.3.1-1' for 'zlib1g' was not found (#10096) 2024-11-07 17:38:10 +08:00
-LAN-
b7534b764d feat(app_dsl_service): enhance error handling and DSL version management (#10108) 2024-11-07 17:38:09 +08:00
非法操作
eb335ed464 chore: save uploaded file extension as lower case (#10111) 2024-11-07 17:38:09 +08:00
-LAN-
4d9e7c1884 refactor(version): simplify version comparison logic (#10109) 2024-11-07 17:38:09 +08:00
beginnerZhang
8f7cac6bde fix: view logs in prompt, no response when clicked (#10093)
Co-authored-by: zhanganguo <zhanganguo@lixiang.com>
2024-11-07 17:38:08 +08:00
非法操作
d4608f0571 chore: remove an unnecessary link (#10088) 2024-11-07 17:38:08 +08:00
非法操作
9f27b5bb12 feat: enhance comfyui workflow (#10085) 2024-11-07 17:38:07 +08:00
AkaraChen
fb9c54e35f build: update docker login action (#10050) 2024-11-07 17:38:07 +08:00
Kota-Yamaguchi
dea45682bc chore: update type definition to resolve lint error in Base usage at text-editor.tsx (#10083) 2024-11-07 17:38:06 +08:00
Bowen Liang
a0abd5d077 improve: significantly speed up the server launching time by async preloading tool providers (#9146) 2024-11-07 17:38:05 +08:00
Charlie.Wei
924dbc128d fix azure chatgpt o1 parameter error (#10067) 2024-11-07 17:38:05 +08:00
crazywoola
b76aa11919 Revert "chore: improve validation and handler of logging timezone with TimezoneName" (#10077) 2024-11-07 17:38:05 +08:00
sacryu
7971efd23e fix the typos in the hit testing template (#10072) 2024-11-07 17:38:04 +08:00
JasonVV
b8c2e5359b Fixed the issue where recall the knowledge base in the iteration of the workflow and report errors when executing (#10060) 2024-11-07 17:38:04 +08:00
Hiroshi Fujita
952847ed29 chore: Set file size limits for video and audio uploads from docker env (#10063) 2024-11-07 17:38:03 +08:00
Fog3211
4e4a8a327b fix: prevent onChange during IME composition (#10059) 2024-11-07 17:38:03 +08:00
22mSqRi
8d1591e5d5 fix: fix poetry install command in devcontainer (#9507) 2024-11-07 17:38:03 +08:00
-LAN-
4b8896e034 fix(workflow): refine variable type checks in LLMNode (#10051) 2024-11-07 17:38:02 +08:00
非法操作
c2d3464a17 chore: mount config file of sandbox (#8576) 2024-11-07 17:38:02 +08:00
zhuhao
0886c6f224 fix: resolve the incorrect model name of hunyuan-standard-256k (#10052) 2024-11-07 17:38:01 +08:00
zhuhao
1ee4c13758 chore: use dify_config.TIDB_SPEND_LIMIT instead of constant value (#10038) 2024-11-07 17:38:01 +08:00
郭伟伟
c293aceec1 feat: /conversations api response add 'update_at' field,and update api docs add sort_by parameter (#10043) 2024-11-07 17:38:01 +08:00
zhuhao
4d5752fc94 feat: add YAML type in document extractor node (#9997) 2024-11-07 17:38:00 +08:00
Xiao Ley
c615ed57b9 add PROMPT_GENERATION_MAX_TOKENS and CODE_GENERATION_MAX_TOKENS in docker enviromment (#10040) 2024-11-07 17:38:00 +08:00
twwu
020d4baf92 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 16:52:26 +08:00
twwu
3f8a10613d refactor: remove unused fetchInstalledPluginList function and integrate useInstalledPluginList hook 2024-11-07 16:52:22 +08:00
AkaraChen
53fa13f007 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 16:44:46 +08:00
AkaraChen
d00e1067bf fix: develop page docs style 2024-11-07 16:44:05 +08:00
Joel
2dd9c64d34 chore: use query 2024-11-07 16:42:44 +08:00
AkaraChen
b7c40579b2 build: update tailwind 2024-11-07 16:41:35 +08:00
twwu
c7f8a0fc7b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 16:06:13 +08:00
twwu
de24d9c145 fix: handle empty fetched releases and update locale usage in plugin item 2024-11-07 16:06:08 +08:00
AkaraChen
6357e1516e build: update react-hook-form 2024-11-07 15:47:07 +08:00
StyleZhang
b83dc5ab99 fix: marketplace 2024-11-07 15:37:39 +08:00
Yi
65285965b6 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 15:31:42 +08:00
Yi
035c9eb147 fix: propagation from closing tag in filters 2024-11-07 15:31:11 +08:00
Joel
91b3aec292 feat: add use tools 2024-11-07 15:24:17 +08:00
AkaraChen
d3a9747bbd build: update @floating-ui/react 2024-11-07 15:22:00 +08:00
StyleZhang
6a99fab92f fix: marketplace 2024-11-07 15:07:07 +08:00
Yi
2a590f6d2b Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 13:42:45 +08:00
Yi
117b0f20dd chore: update the plugin install dropdown styling 2024-11-07 13:42:34 +08:00
StyleZhang
c445f747b7 fix: prompt editor 2024-11-07 12:11:26 +08:00
AkaraChen
8ed0963c6b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 11:46:32 +08:00
Yi
6c47e0b5d1 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 11:37:21 +08:00
Yi
e99e87269e chore: update the selectPackage component 2024-11-07 11:37:05 +08:00
AkaraChen
0a1319548a build: update react markdown
build: update react markdown

build: update react markdown
2024-11-07 11:34:55 +08:00
AkaraChen
b1242ba1ac build: init @tanstack/react-query 2024-11-07 09:44:36 +08:00
twwu
fde0e6c7f9 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-06 18:43:31 +08:00
twwu
92153328ea feat: add loading state for installed plugin list in context and update PluginsPanel to display loading indicator 2024-11-06 18:43:27 +08:00
Joel
e66ba6ffdd chore: fill repo url 2024-11-06 18:13:15 +08:00
twwu
a7e320dc25 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-06 16:58:56 +08:00
twwu
5008d9f4a0 feat: add onSuccess callback to InstallFromGitHub and update plugin list on install actions 2024-11-06 16:58:52 +08:00
Yi
912f84777b Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-06 16:49:29 +08:00
Yi
4c0e4e490a chore: update the 'Update plugin from GitHub' 2024-11-06 16:49:16 +08:00
Joel
306843fe6a chore: plugin info 2024-11-06 16:42:32 +08:00
twwu
b6a4af4041 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-06 16:18:25 +08:00
twwu
cce39b85e9 feat: enhance plugin filtering with tags support 2024-11-06 16:18:18 +08:00
Joel
057d380119 feat: add install model plugin 2024-11-06 15:57:50 +08:00
Joel
4cf9ff6132 chore: remove log 2024-11-06 15:44:49 +08:00
Joel
4cfbcd9c79 feat: add install 2024-11-06 15:42:48 +08:00
StyleZhang
fcde5b5c9e fix: detail 2024-11-06 15:37:12 +08:00
StyleZhang
21b3703bd8 fix: i18n 2024-11-06 15:23:38 +08:00
StyleZhang
9025e85ca5 locale 2024-11-06 15:00:37 +08:00
StyleZhang
bc43e3a9fe card locale 2024-11-06 14:52:47 +08:00
StyleZhang
319a54aa2f i18n 2024-11-06 14:37:20 +08:00
StyleZhang
7c2ab21c9c i18n 2024-11-06 11:55:19 +08:00
twwu
0d08b6cf51 fix: enhance plugin installation and update handling 2024-11-06 09:50:05 +08:00
Yi
61a70e7a71 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 17:53:03 +08:00
Yi
bde1261b8c chore: update installFromGitHub component 2024-11-05 17:52:47 +08:00
StyleZhang
08bb6bf858 fix: tags 2024-11-05 17:35:47 +08:00
twwu
1003190dc0 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-05 16:54:57 +08:00
twwu
4c516a50b8 fix: update type from InstalledPlugin to PluginDetail in detail-header component 2024-11-05 16:53:54 +08:00
Joel
8058a1dbe4 feat: handle update 2024-11-05 16:47:26 +08:00
Yi
8533ded335 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 16:36:55 +08:00
twwu
1a547b0db9 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-05 16:25:38 +08:00
twwu
0b90625e57 feat: integrate GitHub API for plugin version check and add access token support 2024-11-05 16:25:20 +08:00
Joel
e989c1f3aa feat: fill update install payload 2024-11-05 16:04:52 +08:00
Joel
da15a25cf5 feat: add update from github modal content 2024-11-05 15:27:08 +08:00
Joel
43254ceeb0 chore: temp types 2024-11-05 15:22:48 +08:00
Yi
faf550164d Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 15:21:54 +08:00
Yi
1a4234347a chore: update the installFromGitHub logic 2024-11-05 15:21:45 +08:00
Joel
85947efcfa temp: change payload types 2024-11-05 15:21:07 +08:00
Joel
474ea97fc7 feat: add update to modal context 2024-11-05 15:11:55 +08:00
StyleZhang
a3becde6d8 feat: plugin tags 2024-11-05 15:07:24 +08:00
Yi
c40544a134 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 11:41:03 +08:00
Yi
4028bb4f58 chore: update installPluginFromGitHub component 2024-11-05 11:40:52 +08:00
twwu
52268460a1 fix: update dependency in Empty component to improve rendering logic 2024-11-05 11:19:04 +08:00
twwu
b64298c458 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-05 11:05:20 +08:00
twwu
16dee11589 feat: add Empty component to installed plugin list 2024-11-05 11:05:14 +08:00
Yi
691dbf9d17 chore: update plugin from GitHub 2024-11-05 11:02:57 +08:00
JzoNg
ebebbb684b endpoints list 2024-11-02 15:36:38 +08:00
JzoNg
cee51ac084 need author judgement 2024-11-02 15:36:38 +08:00
JzoNg
ef00ad0417 action list 2024-11-02 15:36:38 +08:00
JzoNg
c37615cd33 plugin detail delete handler 2024-11-02 15:36:38 +08:00
JzoNg
a387cfbc9a model list in plugin detail 2024-11-02 15:36:38 +08:00
JzoNg
04fdb4af0f plugin header operation 2024-11-02 15:36:38 +08:00
JzoNg
57f9a41e7f plugin detail selecting 2024-11-02 15:36:38 +08:00
JzoNg
eb8b827906 verified tag 2024-11-02 15:36:38 +08:00
Joel
99a9bf6d56 feat: support search from marketplace list 2024-11-01 18:36:24 +08:00
Yi
ceae69b773 chore: update the workspace selector 2024-11-01 16:48:40 +08:00
Joel
3c8548c562 feat: create tool model 2024-11-01 16:14:01 +08:00
StyleZhang
8874837dc3 feat: plugin tasks 2024-11-01 16:08:31 +08:00
Yi
40e171c2c6 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-01 15:40:06 +08:00
Yi
824ed7d6c2 chore: plugin button 2024-11-01 15:39:55 +08:00
JzoNg
4caa8f38bc hide plugin detail 2024-11-01 15:33:15 +08:00
Joel
5d5db7c6c1 fix: key too long breaks ui 2024-11-01 15:28:10 +08:00
Joel
ca50522f80 feat: set tool params 2024-11-01 15:21:38 +08:00
Yi
2fd4b6e6d2 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-01 14:56:11 +08:00
Yi
c503e8ebc9 chore: install package from GitHub 2024-11-01 14:55:56 +08:00
Joel
245bb02c88 chore: add on start to install 2024-11-01 14:51:35 +08:00
Joel
9f08206503 feat: can choose tool in agent page 2024-11-01 14:41:27 +08:00
Joel
66be03f622 fix: search tools ui and some ui problem 2024-11-01 14:02:10 +08:00
JzoNg
1a92064260 remove unused components 2024-11-01 12:09:17 +08:00
JzoNg
7752f374e5 Revert "update model provider api responses"
This reverts commit c8dc5e4849.
2024-11-01 12:00:54 +08:00
JzoNg
e7dcc53b55 Revert "load balance"
This reverts commit 378a9dd850.
2024-11-01 12:00:54 +08:00
JzoNg
22766c27c7 Revert "model list of provider"
This reverts commit 766ac3e255.
2024-11-01 12:00:54 +08:00
JzoNg
c82b641357 Revert "get credentials of provider"
This reverts commit 72ef04d3e4.
2024-11-01 12:00:54 +08:00
JzoNg
1d871dae0d Revert "credentials of models"
This reverts commit 2ed73b763d.
2024-11-01 12:00:54 +08:00
JzoNg
c39be7852f Revert "parameters and rules"
This reverts commit 22696fa75b.
2024-11-01 12:00:54 +08:00
JzoNg
f2a5da918b Revert "other providers"
This reverts commit 339dfe5e02.
2024-11-01 12:00:54 +08:00
JzoNg
930425b896 Revert "annotation config"
This reverts commit 633768cd2a.
2024-11-01 12:00:54 +08:00
JzoNg
32e4efb524 Revert "logs"
This reverts commit 06729f6d9d.
2024-11-01 12:00:54 +08:00
JzoNg
96c3ec91af click handle of provider card 2024-11-01 12:00:54 +08:00
JzoNg
f257184b00 provider card & link 2024-11-01 12:00:54 +08:00
JzoNg
581d09895e search model in provider settings 2024-11-01 12:00:54 +08:00
StyleZhang
197f1b3957 feat: search box 2024-11-01 11:26:36 +08:00
Joel
207b589458 chore: toolpicker add trigger 2024-11-01 11:22:18 +08:00
StyleZhang
b5be6bacef fix: marketplace list 2024-10-31 18:54:33 +08:00
Joel
bca99cf4f8 feat: tool picker 2024-10-31 18:37:50 +08:00
twwu
0e873223d7 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-31 18:32:32 +08:00
twwu
133b487566 feat: Enhance plugin item links and increase value display width 2024-10-31 18:32:25 +08:00
StyleZhang
a9e8eb1c7e fix: marketplace list 2024-10-31 18:31:36 +08:00
twwu
bf2b9bb898 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-31 16:44:08 +08:00
twwu
837990cb80 feat: Add loading to delete confirmation dialog 2024-10-31 16:44:04 +08:00
StyleZhang
4be2edd934 feat: plugin list tasks 2024-10-31 16:27:24 +08:00
twwu
7d4f8e0082 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-31 16:20:31 +08:00
twwu
36ab121b87 feat: plugin uninstall & plugin list filtering 2024-10-31 16:20:25 +08:00
Joel
7f2980fbc0 chore: fix index show 2024-10-31 16:10:48 +08:00
Joel
ae21d48132 feat: list flat view 2024-10-31 15:59:39 +08:00
StyleZhang
8af8a0f46d fix: tool list 2024-10-31 15:41:02 +08:00
twwu
4adb61d6c7 refactor: Update marketplace API prefix in layout.tsx 2024-10-31 13:45:46 +08:00
Joel
7dd7f06f7d chore: handle icon toggle fold 2024-10-31 12:00:11 +08:00
Joel
074e660a67 feat: can add tree view 2024-10-31 11:37:55 +08:00
JzoNg
06729f6d9d logs 2024-10-31 09:06:10 +08:00
JzoNg
633768cd2a annotation config 2024-10-31 08:43:12 +08:00
JzoNg
339dfe5e02 other providers 2024-10-31 08:22:14 +08:00
JzoNg
22696fa75b parameters and rules 2024-10-31 08:22:14 +08:00
JzoNg
2ed73b763d credentials of models 2024-10-31 08:22:14 +08:00
JzoNg
72ef04d3e4 get credentials of provider 2024-10-31 08:22:14 +08:00
JzoNg
766ac3e255 model list of provider 2024-10-31 08:22:14 +08:00
JzoNg
378a9dd850 load balance 2024-10-31 08:22:14 +08:00
JzoNg
c8dc5e4849 update model provider api responses 2024-10-31 08:22:14 +08:00
JzoNg
1387c6bd1c update style of agent tool list 2024-10-31 08:22:14 +08:00
JzoNg
fda21f6b05 fix size of icon 2024-10-31 08:22:14 +08:00
JzoNg
8c25915d2b action panel tabs 2024-10-31 08:22:14 +08:00
JzoNg
aba48749da action panel header 2024-10-31 08:22:14 +08:00
JzoNg
35a66ffe9f tool actions 2024-10-31 08:22:14 +08:00
StyleZhang
3db9174f55 fix: marketplace list 2024-10-30 17:24:46 +08:00
StyleZhang
02854b273f fix: marketplace 2024-10-30 16:36:08 +08:00
StyleZhang
fd0a830816 feat: marketplace list 2024-10-30 15:27:38 +08:00
StyleZhang
e7fb92e169 feat: marketplace list 2024-10-30 15:16:13 +08:00
Joel
9c4e809799 chore: tiny css and i18n 2024-10-30 14:27:39 +08:00
Joel
169eb32662 chore: toolpicker ui 2024-10-30 14:24:00 +08:00
StyleZhang
0f4291bd36 merge main 2024-10-30 11:20:20 +08:00
StyleZhang
14b641557a feat: marketplace sort 2024-10-30 11:07:13 +08:00
AkaraChen
9c963d6f69 build: echarts update 2024-10-30 10:29:10 +08:00
AkaraChen
96abeda2e7 build: echarts update 2024-10-30 10:28:22 +08:00
StyleZhang
62fa90e30e feat: marketplace sort 2024-10-29 18:14:05 +08:00
Joel
7e378e219c chore: add missing i18n 2024-10-29 18:11:09 +08:00
Joel
34652010f5 feat: add market url prefix 2024-10-29 18:09:59 +08:00
AkaraChen
082f6f6a5f build: update deps 2024-10-29 17:47:06 +08:00
Joel
6f52edb157 feat: plugin permission 2024-10-29 17:18:23 +08:00
Joel
0dcbb34cab feat: handle from market install 2024-10-29 16:33:46 +08:00
StyleZhang
0886d7bb8b feat: marketplace list 2024-10-29 15:23:29 +08:00
StyleZhang
e65a47cff7 feat: marketplace list 2024-10-29 15:23:29 +08:00
Joel
36c01d89c9 fix: cros promblem 2024-10-29 15:19:47 +08:00
Joel
6726ca102e feat: add get marketpalce get 2024-10-29 14:53:14 +08:00
Joel
e135707f88 chore: plugin icon not show 2024-10-29 11:57:21 +08:00
Joel
f2765b9d31 feat: fetch plugin icon 2024-10-29 11:47:23 +08:00
StyleZhang
1e0877dcbf feat: marketplace list 2024-10-29 11:33:52 +08:00
StyleZhang
9a65c3391b feat: marketplace list 2024-10-29 10:51:41 +08:00
Joel
ca9e23d6ea fix: check status 2024-10-28 18:36:23 +08:00
AkaraChen
c4d6f9e179 build: update react-easy-crop 2024-10-28 16:46:35 +08:00
Joel
0cec6195a3 test 2024-10-28 16:33:02 +08:00
Joel
966d42a4db Merge branch 'main' into feat/plugins 2024-10-28 15:53:39 +08:00
AkaraChen
15c33ba7f3 build: update lexical deps 2024-10-28 15:33:22 +08:00
AkaraChen
ed7f74c99c build: update i18n pkg 2024-10-28 15:32:39 +08:00
AkaraChen
1db4139b5a build: update deps
build: update classnames

build: update types

build: update uuid

build: update emoji-mart

build: update use-context-selector

build: update ui component deps
2024-10-28 15:24:44 +08:00
StyleZhang
0d85d44de5 feat: marketplace list 2024-10-28 11:50:45 +08:00
AkaraChen
f0f1bfa5d9 build: fix eslint 2024-10-28 11:03:43 +08:00
Joel
9161ce481e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-28 10:59:39 +08:00
Joel
c760902e72 chore: remove useless rule 2024-10-28 10:56:52 +08:00
Joel
7c8c15ef1a test no use rule 2024-10-28 10:56:31 +08:00
Joel
765eb282f3 merge main 2024-10-28 10:51:02 +08:00
AkaraChen
0e2b38dddc build: update qrcode.react 2024-10-25 18:03:25 +08:00
AkaraChen
92e4b3304c build: update deps
build: update sass

build: update lodash-es

build: update qs & js-cookie
2024-10-25 17:58:19 +08:00
Joel
c777d55a1c feat: marketplace install 2024-10-25 16:46:02 +08:00
AkaraChen
cd27ae4319 build: update testing-library 2024-10-25 13:01:39 +08:00
AkaraChen
bd82c7edac build: update storybook 2024-10-25 13:01:39 +08:00
AkaraChen
d5043c6628 build: update husky & lint-staged 2024-10-25 13:01:39 +08:00
AkaraChen
d9a0584052 build: update eslint & fix some case 2024-10-25 12:51:11 +08:00
Joel
3e011109ad merge main 2024-10-25 11:26:49 +08:00
Joel
bdb990eb90 merge main 2024-10-25 11:26:48 +08:00
StyleZhang
ae00211691 feat: marketplace types 2024-10-25 11:15:32 +08:00
StyleZhang
0ef35a0ee0 fix: enable_marketplace 2024-10-25 10:41:25 +08:00
Joel
9a9d90ad7f feat: can install 2024-10-24 17:24:46 +08:00
Joel
606fc7be0c feat: support upload pkg 2024-10-24 17:14:17 +08:00
Joel
d7def41acc feat: fetch debug key api 2024-10-24 16:07:46 +08:00
AkaraChen
b6a560ce86 style: lint 2024-10-24 14:52:07 +08:00
StyleZhang
25f34f6703 fix: marketplace plugin type icon 2024-10-24 14:21:12 +08:00
Joel
7daa365564 chore: to common install comp 2024-10-24 11:10:44 +08:00
Joel
13ccd294cb fix: install error title not update 2024-10-23 17:55:25 +08:00
Joel
d357f359ab feat: support install failed 2024-10-23 17:52:39 +08:00
Joel
474cedf653 feat: debug info api 2024-10-23 17:19:54 +08:00
nite-knite
5d3c88a0b3 chore: bump mermaid from 10.4.0 to 10.9.3 2024-10-23 17:02:38 +08:00
Joel
ae2c76bda2 feat: install from marketplace 2024-10-23 16:42:24 +08:00
Joel
c46b5f2fd0 feat: handle install search params and hide 2024-10-23 15:26:31 +08:00
Joel
2cb7b73ee7 feat: handle import from marketplace 2024-10-23 15:00:31 +08:00
Joel
8d8d5b5235 chore: handle verified 2024-10-23 11:45:36 +08:00
Joel
15acfffd60 chore: some ui and mock data 2024-10-23 11:40:56 +08:00
Yi
18a266eac2 chore: i18n for install from GitHub section 2024-10-22 18:39:23 +08:00
Joel
7751070da8 chore: install from local i18n 2024-10-22 18:11:54 +08:00
Yi
fa8c3d0d7b Resolved merge conflicts by removing conflicting files 2024-10-22 17:58:41 +08:00
Yi
a567cff809 chore: update the install from GitHub component 2024-10-22 17:51:14 +08:00
Joel
583b0e9f97 chore: remove replicated types 2024-10-22 17:29:58 +08:00
Joel
5fddb23516 feat: install progress 2024-10-22 17:21:44 +08:00
Yi
0e52971997 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-22 16:40:50 +08:00
Yi
1387f406a3 fix: log format 2024-10-22 16:40:27 +08:00
AkaraChen
ff31f0540a style: lint 2024-10-22 15:32:58 +08:00
AkaraChen
4873e6e2a1 build: fix eslint stylistic 2024-10-22 15:32:48 +08:00
nite-knite
510ce057f7 chore: add package manager setting to vscode setting example 2024-10-22 14:18:55 +08:00
AkaraChen
0e53cc0e8c fix: eslint indent 2024-10-22 14:15:22 +08:00
Yi
0b8c896481 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-22 13:43:15 +08:00
Yi
15fe635465 chore: install package from GitHub 2024-10-22 13:43:01 +08:00
AkaraChen
f8c3189f4d build: fix eslint undef 2024-10-22 11:43:23 +08:00
AkaraChen
f215db87e3 build: fix eslint undef 2024-10-22 11:36:42 +08:00
Joel
67d02212b4 chore: pnpm 2024-10-22 11:18:30 +08:00
Joel
cff9adaf8e chore: tools ts problems 2024-10-22 11:06:28 +08:00
AkaraChen
cdd2a40086 style: minimium codemod 2024-10-22 02:24:59 +00:00
AkaraChen
024028bc52 build: sync eslint rule 2024-10-22 10:24:10 +08:00
AkaraChen
0ae085b48a build: add eslint common rule 2024-10-22 10:24:10 +08:00
AkaraChen
2094c54951 build: update eslint config antfu 2024-10-22 10:24:10 +08:00
AkaraChen
f4f11135d3 build: using eslint flat config 2024-10-22 10:24:10 +08:00
Joel
8e9d7a229d feat: scroll to view and fix action hidden 2024-10-21 18:21:45 +08:00
Joel
8f49572f85 chore: from marketplace tilte ui 2024-10-21 15:07:18 +08:00
JzoNg
5aa7696cc3 update style of action list 2024-10-21 11:34:21 +08:00
JzoNg
15dd79e822 provider detail data binding 2024-10-21 11:34:21 +08:00
JzoNg
4651ab4195 new style of provider detail 2024-10-21 11:34:21 +08:00
JzoNg
5e3160e6f6 fix title & description of tool provider 2024-10-21 11:34:21 +08:00
JzoNg
973cd126bb create & update endpoint 2024-10-21 11:34:21 +08:00
JzoNg
ebaf8766ef endpoint form 2024-10-21 11:34:21 +08:00
JzoNg
d2190e9c3a remove endpoint 2024-10-21 11:34:21 +08:00
JzoNg
37f55098fe switch endpoint service state 2024-10-21 11:34:21 +08:00
JzoNg
b1771194cc servise of endpoints 2024-10-21 11:34:21 +08:00
JzoNg
0279bd8c75 endpoint card databing 2024-10-21 11:34:21 +08:00
JzoNg
5e077e4ce8 endpoints data binding 2024-10-21 11:34:21 +08:00
JzoNg
64067e1f20 plugin detail header operations 2024-10-21 11:34:21 +08:00
JzoNg
5295c72ca1 endpoints mock data 2024-10-21 11:34:21 +08:00
JzoNg
1ecea62052 add verified tag 2024-10-21 11:34:21 +08:00
JzoNg
307af29b65 add plugin description 2024-10-21 11:34:21 +08:00
JzoNg
10190a9aa5 plugin detail header data binding 2024-10-21 11:34:21 +08:00
JzoNg
7c5c35600c plugin detail type 2024-10-21 11:34:21 +08:00
JzoNg
63b333cdb1 modify plugin detail panel 2024-10-21 11:34:21 +08:00
JzoNg
a6776190bd chore: update remix icon 2024-10-21 11:34:19 +08:00
AkaraChen
9577cbac27 build: docker use pnpm 2024-10-21 11:27:01 +08:00
AkaraChen
f6ae13abad ci: migrate to pnpm 2024-10-21 11:14:30 +08:00
AkaraChen
f3d501e7d5 fix: gen-icon script phantom deps 2024-10-21 10:43:52 +08:00
AkaraChen
2eab8fcc33 build: switch to pnpm 2024-10-21 10:43:52 +08:00
Joel
bdb81fe20d feat: choose tool sticky 2024-10-18 18:18:59 +08:00
Yi
0f60fe7f2a chore: update workspace name (truncated for long name) 2024-10-18 14:17:53 +08:00
Yi
425f624de5 chore: add plugin panel 2024-10-18 14:02:40 +08:00
Yi
b1919745e2 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-18 14:01:34 +08:00
twwu
9a242bcac9 Merge branch 'main' into feat/plugins 2024-10-18 09:59:43 +08:00
Yi
a6109a60b8 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-17 15:22:08 +08:00
Yi
28f7bbf83a chore: installation progress bar 2024-10-17 15:21:56 +08:00
Joel
cac04c5f3c refactor: chagne card to client component 2024-10-17 15:06:06 +08:00
Joel
18f5f9cc37 feat: plugin upgrade 2024-10-16 18:05:55 +08:00
Joel
1787c5c93f chore: handle tag name too long 2024-10-16 16:39:47 +08:00
Joel
f981494613 feat: plugin support emoji icon 2024-10-16 16:28:19 +08:00
Joel
fbc853af92 feat: remove config 2024-10-16 16:28:18 +08:00
StyleZhang
1a64c660ba enable marketplace 2024-10-16 15:50:18 +08:00
Joel
846555af1b fix: action buttion ui 2024-10-16 11:45:25 +08:00
Joel
bca94854f7 feat: plugin info 2024-10-16 11:30:04 +08:00
Joel
1bd70bd8bf chore: copy button 2024-10-16 11:05:51 +08:00
Joel
d1dcd39191 feat: add debug info i18n and extract common to components 2024-10-16 10:52:16 +08:00
Joel
35384bda41 chore: refactor card loading 2024-10-15 22:52:57 +08:00
Joel
89fb6eb648 chore: set hideCornerMark to optional 2024-10-15 21:45:30 +08:00
Joel
aa61a890b2 chore: change downloadCount to optional 2024-10-15 21:43:20 +08:00
Joel
31ece363c3 chore: chagne mangament attr name 2024-10-15 21:35:56 +08:00
Joel
70a5d78cc5 chore: priviege i18n 2024-10-15 21:31:06 +08:00
Joel
57f4dfdb6f feat: add permission data logic 2024-10-15 19:20:59 +08:00
Yi
aa9028a607 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 15:48:05 +08:00
Yi
d83f94c55c fix: set constrain for uploading packages only works in the Plugins tab 2024-10-15 15:47:54 +08:00
StyleZhang
a8c5e0b0b0 tool list item click 2024-10-15 15:13:00 +08:00
Yi
177e8cbf73 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 14:57:37 +08:00
Yi
23828fd15a Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 14:57:11 +08:00
StyleZhang
2cc37ac8e5 tool list 2024-10-15 14:57:00 +08:00
Yi
c9ee1e9ff2 feat: install difypkg ui 2024-10-15 14:56:59 +08:00
Joel
4f10f5d5f4 chore: hover show action 2024-10-15 11:57:44 +08:00
Yi
c48c84674e Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 11:02:45 +08:00
Yi
1e9fbbf41b fix: dynamic sub header color 2024-10-15 11:02:25 +08:00
StyleZhang
4dd144ce43 tools list 2024-10-15 10:41:10 +08:00
Yi
a387ff1c38 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-14 18:43:24 +08:00
Yi
a9e367e6de feat: use-uploader hook 2024-10-14 18:43:08 +08:00
Joel
e2fec587f8 feat: from marketplace 2024-10-14 18:35:13 +08:00
StyleZhang
39a6f0943d marketplace 2024-10-14 12:38:53 +08:00
JzoNg
684896d100 merge main 2024-10-14 10:29:52 +08:00
JzoNg
54f911f6cd endpoints 2024-10-13 10:49:55 +08:00
Joel
0e5c16d0c2 feat: view to ui and fix some ui promblem 2024-10-12 18:15:11 +08:00
Joel
b8cd6ea478 feat: support view choose 2024-10-12 17:36:35 +08:00
JzoNg
fc61fd0f50 action list 2024-10-12 17:08:45 +08:00
JzoNg
2fbfc988c4 plugin panel detail 2024-10-12 16:37:57 +08:00
JzoNg
99f5fea001 plugin detail panel header 2024-10-12 16:37:57 +08:00
StyleZhang
ecd2a1be9f marketplace 2024-10-12 16:34:18 +08:00
Joel
49ee9ca5f1 feat: tool item support action 2024-10-12 16:04:16 +08:00
Joel
6d0eef12b1 feat: split tools data to out and add demo 2024-10-12 14:30:46 +08:00
StyleZhang
c1e0a939b0 marketplace 2024-10-12 12:46:49 +08:00
JzoNg
060a894bd1 interaction of plugin detail panel 2024-10-12 12:36:29 +08:00
JzoNg
c75e02b5b2 update provider card 2024-10-12 12:36:29 +08:00
StyleZhang
fcf43ee845 plugin page context 2024-10-12 11:33:12 +08:00
StyleZhang
466f61d044 relocate file 2024-10-12 11:05:03 +08:00
StyleZhang
27ae74af50 hook 2024-10-12 11:03:00 +08:00
Joel
8dd941e3d2 chore: instal plug add tag 2024-10-11 18:18:32 +08:00
Joel
dec4bf6b98 fix: install modal item server 2024-10-11 18:06:23 +08:00
Joel
e2c33fc40f fix: plugin item i18n 2024-10-11 18:05:45 +08:00
Yi
c74e59d1f4 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-11 17:28:27 +08:00
Yi
1fcb902715 feat: add cards to "install from marketplace" 2024-10-11 17:25:33 +08:00
JzoNg
c08f98218c hide search in other pages 2024-10-11 17:13:28 +08:00
Yi
c6377f6e38 fix: naming styles 2024-10-11 16:29:07 +08:00
Yi
3cb0a5bd68 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-11 16:28:04 +08:00
Yi
95777d23e0 fix: naming styles 2024-10-11 16:27:31 +08:00
JzoNg
e7dc16fd08 provider card 2024-10-11 16:21:19 +08:00
JzoNg
495dec143c unconfigured provider 2024-10-11 16:21:19 +08:00
JzoNg
4cc6dfa232 new style of provider card 2024-10-11 16:21:18 +08:00
JzoNg
d1452d4af4 no provider installed 2024-10-11 16:21:18 +08:00
JzoNg
d68ca56b3a system default model 2024-10-11 16:21:18 +08:00
JzoNg
49856d8d17 setting content header & close button 2024-10-11 16:21:18 +08:00
JzoNg
902de72cc0 new style of settings 2024-10-11 16:21:18 +08:00
StyleZhang
76f6b8d104 marketplace 2024-10-11 16:15:24 +08:00
StyleZhang
f111e605c4 marketplace 2024-10-11 15:27:14 +08:00
Joel
b358ed3a5b fix: init workflow image crash 2024-10-11 14:31:14 +08:00
Joel
88dbf639e0 chore: enchance locale props 2024-10-11 14:24:43 +08:00
Joel
aa8b525b48 fix: icon tsx to router problem 2024-10-11 14:10:24 +08:00
Yi
c990bc61db feat: install plugins (partial) 2024-10-11 12:39:27 +08:00
Joel
6d7588f236 chore: fix ui 2024-10-10 17:53:13 +08:00
Joel
8257c7bf02 chore: remove useless data 2024-10-10 17:49:23 +08:00
Joel
946068967b feat: finish card components 2024-10-10 17:47:04 +08:00
Joel
19f5684960 feat: add label and fix some ui problem 2024-10-10 11:29:11 +08:00
Joel
6d62840aff chore: split card component 2024-10-10 10:40:26 +08:00
Joel
ab868ac979 fix: error igm 2024-10-10 10:25:25 +08:00
Joel
1d74e693ea chore: fix imge name 2024-10-10 10:22:18 +08:00
Joel
fa43d4202f feat: plugin item 2024-10-09 18:36:15 +08:00
Joel
6b29860788 feat: add installed 2024-10-09 18:12:14 +08:00
Joel
36800eeaba feat: base card component 2024-10-09 17:51:54 +08:00
Yi
67acd174ac add different styles to plugins and discover 2024-10-09 15:55:33 +08:00
StyleZhang
b5edc64b2a plugin type switch 2024-10-09 15:06:09 +08:00
Yi
d00b2724cc Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-09 12:53:56 +08:00
Yi
43f87c0b86 make the drop plugin only appears when the user selects "plugins" 2024-10-09 12:53:43 +08:00
Joel
7a43f48c95 chore: add test page 2024-10-09 11:35:16 +08:00
StyleZhang
58a913b09d marketplace 2024-10-08 17:58:05 +08:00
Joel
cd03795f2c chore: add endpoint types 2024-10-08 15:44:52 +08:00
Joel
36f8b5711d feat: plugin types 2024-09-30 15:29:53 +08:00
Joel
f9c48e9ea9 fix: eslint to find top dir 2024-09-29 18:27:36 +08:00
JzoNg
3b48f8c98e Merge branch 'main' into tp 2024-09-27 16:47:57 +08:00
JzoNg
cef1010cb5 style update 2024-09-27 16:47:01 +08:00
Joel
cb4875a3a7 chore: split the common tailwind config 2024-09-26 15:06:36 +08:00
StyleZhang
bbca708832 add marketplace card 2024-09-24 11:18:34 +08:00
JzoNg
05aec43ee3 Merge branch 'main' into tp 2024-09-23 11:39:46 +08:00
Yi
e8127756e0 Merge branch 'main' of github.com:langgenius/dify into feat/plugins 2024-09-18 20:57:52 +08:00
Yi
792595a46f update page header 2024-09-18 18:32:33 +08:00
Yi
d7d7281c93 feat: plugin homepage 2024-09-16 18:58:39 +08:00
Yi
21193c2fbf update the plugins page 2024-09-14 17:09:25 +08:00
561 changed files with 33320 additions and 2673 deletions

View File

@ -1,11 +1,12 @@
#!/bin/bash #!/bin/bash
cd web && npm install npm add -g pnpm@9.12.2
cd web && pnpm install
pipx install poetry pipx install poetry
echo 'alias start-api="cd /workspaces/dify/api && poetry run python -m flask run --host 0.0.0.0 --port=5001 --debug"' >> ~/.bashrc echo 'alias start-api="cd /workspaces/dify/api && poetry run python -m flask run --host 0.0.0.0 --port=5001 --debug"' >> ~/.bashrc
echo 'alias start-worker="cd /workspaces/dify/api && poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion"' >> ~/.bashrc echo 'alias start-worker="cd /workspaces/dify/api && poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion"' >> ~/.bashrc
echo 'alias start-web="cd /workspaces/dify/web && npm run dev"' >> ~/.bashrc echo 'alias start-web="cd /workspaces/dify/web && pnpm dev"' >> ~/.bashrc
echo 'alias start-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify up -d"' >> ~/.bashrc echo 'alias start-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify up -d"' >> ~/.bashrc
source /home/vscode/.bashrc source /home/vscode/.bashrc

View File

@ -76,16 +76,16 @@ jobs:
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
with: with:
node-version: 20 node-version: 20
cache: yarn cache: pnpm
cache-dependency-path: ./web/package.json cache-dependency-path: ./web/package.json
- name: Web dependencies - name: Web dependencies
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
run: yarn install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Web style check - name: Web style check
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
run: yarn run lint run: pnpm run lint
superlinter: superlinter:

View File

@ -32,10 +32,10 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: '' cache: ''
cache-dependency-path: 'yarn.lock' cache-dependency-path: 'pnpm-lock.yaml'
- name: Install Dependencies - name: Install Dependencies
run: yarn install run: pnpm install
- name: Test - name: Test
run: yarn test run: pnpm test

View File

@ -38,11 +38,11 @@ jobs:
- name: Install dependencies - name: Install dependencies
if: env.FILES_CHANGED == 'true' if: env.FILES_CHANGED == 'true'
run: yarn install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Run npm script - name: Run npm script
if: env.FILES_CHANGED == 'true' if: env.FILES_CHANGED == 'true'
run: npm run auto-gen-i18n run: pnpm run auto-gen-i18n
- name: Create Pull Request - name: Create Pull Request
if: env.FILES_CHANGED == 'true' if: env.FILES_CHANGED == 'true'

View File

@ -34,13 +34,13 @@ jobs:
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
with: with:
node-version: 20 node-version: 20
cache: yarn cache: pnpm
cache-dependency-path: ./web/package.json cache-dependency-path: ./web/package.json
- name: Install dependencies - name: Install dependencies
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
run: yarn install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Run tests - name: Run tests
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
run: yarn test run: pnpm test

3
.gitignore vendored
View File

@ -193,3 +193,6 @@ api/.vscode
.idea/ .idea/
.vscode .vscode
# pnpm
/.pnpm-store

View File

@ -54,10 +54,12 @@ def make_request(method, url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
if response.status_code not in STATUS_FORCELIST: if response.status_code not in STATUS_FORCELIST:
return response return response
else: else:
logging.warning(f"Received status code {response.status_code} for URL {url} which is in the force list") logging.warning(
f"Received status code {response.status_code} for URL {url} which is in the force list")
except httpx.RequestError as e: except httpx.RequestError as e:
logging.warning(f"Request to URL {url} failed on attempt {retries + 1}: {e}") logging.warning(
f"Request to URL {url} failed on attempt {retries + 1}: {e}")
retries += 1 retries += 1
if retries <= max_retries: if retries <= max_retries:

View File

@ -20,7 +20,8 @@ from extensions.ext_redis import redis_client
from models.dataset import Dataset from models.dataset import Dataset
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logging.basicConfig(level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s")
logging.getLogger("lindorm").setLevel(logging.WARN) logging.getLogger("lindorm").setLevel(logging.WARN)
@ -76,7 +77,8 @@ class LindormVectorStore(BaseVector):
@retry(stop=stop_after_attempt(3), wait=wait_fixed(60)) @retry(stop=stop_after_attempt(3), wait=wait_fixed(60))
def __fetch_existing_ids(batch_ids: list[str]) -> set[str]: def __fetch_existing_ids(batch_ids: list[str]) -> set[str]:
try: try:
existing_docs = self._client.mget(index=self._collection_name, body={"ids": batch_ids}, _source=False) existing_docs = self._client.mget(index=self._collection_name, body={
"ids": batch_ids}, _source=False)
return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]} return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]}
except Exception as e: except Exception as e:
logger.exception(f"Error fetching batch {batch_ids}: {e}") logger.exception(f"Error fetching batch {batch_ids}: {e}")
@ -88,7 +90,8 @@ class LindormVectorStore(BaseVector):
existing_docs = self._client.mget( existing_docs = self._client.mget(
body={ body={
"docs": [ "docs": [
{"_index": self._collection_name, "_id": id, "routing": routing} {"_index": self._collection_name,
"_id": id, "routing": routing}
for id, routing in zip(batch_ids, route_ids) for id, routing in zip(batch_ids, route_ids)
] ]
}, },
@ -117,7 +120,8 @@ class LindormVectorStore(BaseVector):
for ids_batch, texts_batch, metadatas_batch in zip( for ids_batch, texts_batch, metadatas_batch in zip(
batch(ids, bulk_size), batch(ids, bulk_size),
batch(texts, bulk_size), batch(texts, bulk_size),
batch(metadatas, bulk_size) if metadatas is not None else batch([None] * len(ids), bulk_size), batch(metadatas, bulk_size) if metadatas is not None else batch(
[None] * len(ids), bulk_size),
): ):
existing_ids_set = __fetch_existing_ids(ids_batch) existing_ids_set = __fetch_existing_ids(ids_batch)
for text, metadata, doc_id in zip(texts_batch, metadatas_batch, ids_batch): for text, metadata, doc_id in zip(texts_batch, metadatas_batch, ids_batch):
@ -139,7 +143,8 @@ class LindormVectorStore(BaseVector):
"_id": uuids[i], "_id": uuids[i],
"_source": { "_source": {
Field.CONTENT_KEY.value: documents[i].page_content, Field.CONTENT_KEY.value: documents[i].page_content,
Field.VECTOR.value: embeddings[i], # Make sure you pass an array here # Make sure you pass an array here
Field.VECTOR.value: embeddings[i],
Field.METADATA_KEY.value: documents[i].metadata, Field.METADATA_KEY.value: documents[i].metadata,
}, },
} }
@ -148,7 +153,8 @@ class LindormVectorStore(BaseVector):
self.refresh() self.refresh()
def get_ids_by_metadata_field(self, key: str, value: str): def get_ids_by_metadata_field(self, key: str, value: str):
query = {"query": {"term": {f"{Field.METADATA_KEY.value}.{key}.keyword": value}}} query = {
"query": {"term": {f"{Field.METADATA_KEY.value}.{key}.keyword": value}}}
response = self._client.search(index=self._collection_name, body=query) response = self._client.search(index=self._collection_name, body=query)
if response["hits"]["hits"]: if response["hits"]["hits"]:
return [hit["_id"] for hit in response["hits"]["hits"]] return [hit["_id"] for hit in response["hits"]["hits"]]
@ -157,7 +163,8 @@ class LindormVectorStore(BaseVector):
def delete_by_metadata_field(self, key: str, value: str): def delete_by_metadata_field(self, key: str, value: str):
query_str = {"query": {"match": {f"metadata.{key}": f"{value}"}}} query_str = {"query": {"match": {f"metadata.{key}": f"{value}"}}}
results = self._client.search(index=self._collection_name, body=query_str) results = self._client.search(
index=self._collection_name, body=query_str)
ids = [hit["_id"] for hit in results["hits"]["hits"]] ids = [hit["_id"] for hit in results["hits"]["hits"]]
if ids: if ids:
self.delete_by_ids(ids) self.delete_by_ids(ids)
@ -167,15 +174,18 @@ class LindormVectorStore(BaseVector):
if self._client.exists(index=self._collection_name, id=id): if self._client.exists(index=self._collection_name, id=id):
self._client.delete(index=self._collection_name, id=id) self._client.delete(index=self._collection_name, id=id)
else: else:
logger.warning(f"DELETE BY ID: ID {id} does not exist in the index.") logger.warning(
f"DELETE BY ID: ID {id} does not exist in the index.")
def delete(self) -> None: def delete(self) -> None:
try: try:
if self._client.indices.exists(index=self._collection_name): if self._client.indices.exists(index=self._collection_name):
self._client.indices.delete(index=self._collection_name, params={"timeout": 60}) self._client.indices.delete(
index=self._collection_name, params={"timeout": 60})
logger.info("Delete index success") logger.info("Delete index success")
else: else:
logger.warning(f"Index '{self._collection_name}' does not exist. No deletion performed.") logger.warning(
f"Index '{self._collection_name}' does not exist. No deletion performed.")
except Exception as e: except Exception as e:
logger.exception(f"Error occurred while deleting the index: {e}") logger.exception(f"Error occurred while deleting the index: {e}")
raise e raise e
@ -197,9 +207,11 @@ class LindormVectorStore(BaseVector):
raise ValueError("All elements in query_vector should be floats") raise ValueError("All elements in query_vector should be floats")
top_k = kwargs.get("top_k", 10) top_k = kwargs.get("top_k", 10)
query = default_vector_search_query(query_vector=query_vector, k=top_k, **kwargs) query = default_vector_search_query(
query_vector=query_vector, k=top_k, **kwargs)
try: try:
response = self._client.search(index=self._collection_name, body=query) response = self._client.search(
index=self._collection_name, body=query)
except Exception as e: except Exception as e:
logger.exception(f"Error executing search: {e}") logger.exception(f"Error executing search: {e}")
raise raise
@ -244,7 +256,8 @@ class LindormVectorStore(BaseVector):
filters=filters, filters=filters,
routing=routing, routing=routing,
) )
response = self._client.search(index=self._collection_name, body=full_text_query) response = self._client.search(
index=self._collection_name, body=full_text_query)
docs = [] docs = []
for hit in response["hits"]["hits"]: for hit in response["hits"]["hits"]:
docs.append( docs.append(
@ -262,7 +275,8 @@ class LindormVectorStore(BaseVector):
with redis_client.lock(lock_name, timeout=20): with redis_client.lock(lock_name, timeout=20):
collection_exist_cache_key = f"vector_indexing_{self._collection_name}" collection_exist_cache_key = f"vector_indexing_{self._collection_name}"
if redis_client.get(collection_exist_cache_key): if redis_client.get(collection_exist_cache_key):
logger.info(f"Collection {self._collection_name} already exists.") logger.info(
f"Collection {self._collection_name} already exists.")
return return
if self._client.indices.exists(index=self._collection_name): if self._client.indices.exists(index=self._collection_name):
logger.info("{self._collection_name.lower()} already exists.") logger.info("{self._collection_name.lower()} already exists.")
@ -281,10 +295,13 @@ class LindormVectorStore(BaseVector):
hnsw_ef_construction = kwargs.pop("hnsw_ef_construction", 500) hnsw_ef_construction = kwargs.pop("hnsw_ef_construction", 500)
ivfpq_m = kwargs.pop("ivfpq_m", dimension) ivfpq_m = kwargs.pop("ivfpq_m", dimension)
nlist = kwargs.pop("nlist", 1000) nlist = kwargs.pop("nlist", 1000)
centroids_use_hnsw = kwargs.pop("centroids_use_hnsw", True if nlist >= 5000 else False) centroids_use_hnsw = kwargs.pop(
"centroids_use_hnsw", True if nlist >= 5000 else False)
centroids_hnsw_m = kwargs.pop("centroids_hnsw_m", 24) centroids_hnsw_m = kwargs.pop("centroids_hnsw_m", 24)
centroids_hnsw_ef_construct = kwargs.pop("centroids_hnsw_ef_construct", 500) centroids_hnsw_ef_construct = kwargs.pop(
centroids_hnsw_ef_search = kwargs.pop("centroids_hnsw_ef_search", 100) "centroids_hnsw_ef_construct", 500)
centroids_hnsw_ef_search = kwargs.pop(
"centroids_hnsw_ef_search", 100)
mapping = default_text_mapping( mapping = default_text_mapping(
dimension, dimension,
method_name, method_name,
@ -303,7 +320,8 @@ class LindormVectorStore(BaseVector):
centroids_hnsw_ef_search=centroids_hnsw_ef_search, centroids_hnsw_ef_search=centroids_hnsw_ef_search,
**kwargs, **kwargs,
) )
self._client.indices.create(index=self._collection_name.lower(), body=mapping) self._client.indices.create(
index=self._collection_name.lower(), body=mapping)
redis_client.set(collection_exist_cache_key, 1, ex=3600) redis_client.set(collection_exist_cache_key, 1, ex=3600)
# logger.info(f"create index success: {self._collection_name}") # logger.info(f"create index success: {self._collection_name}")
@ -364,7 +382,8 @@ def default_text_mapping(dimension: int, method_name: str, **kwargs: Any) -> dic
} }
if excludes_from_source: if excludes_from_source:
mapping["mappings"]["_source"] = {"excludes": excludes_from_source} # e.g. {"excludes": ["vector_field"]} # e.g. {"excludes": ["vector_field"]}
mapping["mappings"]["_source"] = {"excludes": excludes_from_source}
if method_name == "ivfpq" and routing_field is not None: if method_name == "ivfpq" and routing_field is not None:
mapping["settings"]["index"]["knn_routing"] = True mapping["settings"]["index"]["knn_routing"] = True
@ -405,7 +424,8 @@ def default_text_search_query(
# build complex search_query when either of must/must_not/should/filter is specified # build complex search_query when either of must/must_not/should/filter is specified
if must: if must:
if not isinstance(must, list): if not isinstance(must, list):
raise RuntimeError(f"unexpected [must] clause with {type(filters)}") raise RuntimeError(
f"unexpected [must] clause with {type(filters)}")
if query_clause not in must: if query_clause not in must:
must.append(query_clause) must.append(query_clause)
else: else:
@ -415,19 +435,22 @@ def default_text_search_query(
if must_not: if must_not:
if not isinstance(must_not, list): if not isinstance(must_not, list):
raise RuntimeError(f"unexpected [must_not] clause with {type(filters)}") raise RuntimeError(
f"unexpected [must_not] clause with {type(filters)}")
boolean_query["must_not"] = must_not boolean_query["must_not"] = must_not
if should: if should:
if not isinstance(should, list): if not isinstance(should, list):
raise RuntimeError(f"unexpected [should] clause with {type(filters)}") raise RuntimeError(
f"unexpected [should] clause with {type(filters)}")
boolean_query["should"] = should boolean_query["should"] = should
if minimum_should_match != 0: if minimum_should_match != 0:
boolean_query["minimum_should_match"] = minimum_should_match boolean_query["minimum_should_match"] = minimum_should_match
if filters: if filters:
if not isinstance(filters, list): if not isinstance(filters, list):
raise RuntimeError(f"unexpected [filter] clause with {type(filters)}") raise RuntimeError(
f"unexpected [filter] clause with {type(filters)}")
boolean_query["filter"] = filters boolean_query["filter"] = filters
search_query = {"size": k, "query": {"bool": boolean_query}} search_query = {"size": k, "query": {"bool": boolean_query}}
@ -471,8 +494,10 @@ def default_vector_search_query(
if filters is not None: if filters is not None:
# when using filter, transform filter from List[Dict] to Dict as valid format # when using filter, transform filter from List[Dict] to Dict as valid format
filters = {"bool": {"must": filters}} if len(filters) > 1 else filters[0] filters = {"bool": {"must": filters}} if len(
search_query["query"]["knn"][vector_field]["filter"] = filters # filter should be Dict filters) > 1 else filters[0]
# filter should be Dict
search_query["query"]["knn"][vector_field]["filter"] = filters
if filter_type: if filter_type:
final_ext["lvector"]["filter_type"] = filter_type final_ext["lvector"]["filter_type"] = filter_type
@ -489,7 +514,8 @@ class LindormVectorStoreFactory(AbstractVectorFactory):
else: else:
dataset_id = dataset.id dataset_id = dataset.id
collection_name = Dataset.gen_collection_name_by_id(dataset_id) collection_name = Dataset.gen_collection_name_by_id(dataset_id)
dataset.index_struct = json.dumps(self.gen_index_struct_dict(VectorType.LINDORM, collection_name)) dataset.index_struct = json.dumps(
self.gen_index_struct_dict(VectorType.LINDORM, collection_name))
lindorm_config = LindormVectorStoreConfig( lindorm_config = LindormVectorStoreConfig(
hosts=dify_config.LINDORM_URL, hosts=dify_config.LINDORM_URL,
username=dify_config.LINDORM_USERNAME, username=dify_config.LINDORM_USERNAME,

View File

@ -38,7 +38,6 @@ class AliYuqueDescribeDocumentContentTool(AliYuqueTool, BuiltinTool):
book_id = index_page.get("data", {}).get("book", {}).get("id") book_id = index_page.get("data", {}).get("book", {}).get("id")
if not book_id: if not book_id:
raise Exception(f"can not parse book_id from {index_page}") raise Exception(f"can not parse book_id from {index_page}")
new_params["book_id"] = book_id new_params["book_id"] = book_id
new_params["id"] = doc_id new_params["id"] = doc_id
data = self.request("GET", token, new_params, "/api/v2/repos/{book_id}/docs/{id}") data = self.request("GET", token, new_params, "/api/v2/repos/{book_id}/docs/{id}")

View File

@ -49,11 +49,13 @@ class QuestionClassifierNode(LLMNode):
variable_pool = self.graph_runtime_state.variable_pool variable_pool = self.graph_runtime_state.variable_pool
# extract variables # extract variables
variable = variable_pool.get(node_data.query_variable_selector) if node_data.query_variable_selector else None variable = variable_pool.get(
node_data.query_variable_selector) if node_data.query_variable_selector else None
query = variable.value if variable else None query = variable.value if variable else None
variables = {"query": query} variables = {"query": query}
# fetch model config # fetch model config
model_instance, model_config = self._fetch_model_config(node_data.model) model_instance, model_config = self._fetch_model_config(
node_data.model)
# fetch memory # fetch memory
memory = self._fetch_memory( memory = self._fetch_memory(
node_data_memory=node_data.memory, node_data_memory=node_data.memory,
@ -61,7 +63,8 @@ class QuestionClassifierNode(LLMNode):
) )
# fetch instruction # fetch instruction
node_data.instruction = node_data.instruction or "" node_data.instruction = node_data.instruction or ""
node_data.instruction = variable_pool.convert_template(node_data.instruction).text node_data.instruction = variable_pool.convert_template(
node_data.instruction).text
files: Sequence[File] = ( files: Sequence[File] = (
self._fetch_files( self._fetch_files(
@ -184,12 +187,15 @@ class QuestionClassifierNode(LLMNode):
variable_mapping = {"query": node_data.query_variable_selector} variable_mapping = {"query": node_data.query_variable_selector}
variable_selectors = [] variable_selectors = []
if node_data.instruction: if node_data.instruction:
variable_template_parser = VariableTemplateParser(template=node_data.instruction) variable_template_parser = VariableTemplateParser(
variable_selectors.extend(variable_template_parser.extract_variable_selectors()) template=node_data.instruction)
variable_selectors.extend(
variable_template_parser.extract_variable_selectors())
for variable_selector in variable_selectors: for variable_selector in variable_selectors:
variable_mapping[variable_selector.variable] = variable_selector.value_selector variable_mapping[variable_selector.variable] = variable_selector.value_selector
variable_mapping = {node_id + "." + key: value for key, value in variable_mapping.items()} variable_mapping = {node_id + "." + key: value for key,
value in variable_mapping.items()}
return variable_mapping return variable_mapping
@ -210,7 +216,8 @@ class QuestionClassifierNode(LLMNode):
context: Optional[str], context: Optional[str],
) -> int: ) -> int:
prompt_transform = AdvancedPromptTransform(with_variable_tmpl=True) prompt_transform = AdvancedPromptTransform(with_variable_tmpl=True)
prompt_template = self._get_prompt_template(node_data, query, None, 2000) prompt_template = self._get_prompt_template(
node_data, query, None, 2000)
prompt_messages = prompt_transform.get_prompt( prompt_messages = prompt_transform.get_prompt(
prompt_template=prompt_template, prompt_template=prompt_template,
inputs={}, inputs={},
@ -223,13 +230,15 @@ class QuestionClassifierNode(LLMNode):
) )
rest_tokens = 2000 rest_tokens = 2000
model_context_tokens = model_config.model_schema.model_properties.get(ModelPropertyKey.CONTEXT_SIZE) model_context_tokens = model_config.model_schema.model_properties.get(
ModelPropertyKey.CONTEXT_SIZE)
if model_context_tokens: if model_context_tokens:
model_instance = ModelInstance( model_instance = ModelInstance(
provider_model_bundle=model_config.provider_model_bundle, model=model_config.model provider_model_bundle=model_config.provider_model_bundle, model=model_config.model
) )
curr_message_tokens = model_instance.get_llm_num_tokens(prompt_messages) curr_message_tokens = model_instance.get_llm_num_tokens(
prompt_messages)
max_tokens = 0 max_tokens = 0
for parameter_rule in model_config.model_schema.parameter_rules: for parameter_rule in model_config.model_schema.parameter_rules:
@ -270,7 +279,8 @@ class QuestionClassifierNode(LLMNode):
prompt_messages: list[LLMNodeChatModelMessage] = [] prompt_messages: list[LLMNodeChatModelMessage] = []
if model_mode == ModelMode.CHAT: if model_mode == ModelMode.CHAT:
system_prompt_messages = LLMNodeChatModelMessage( system_prompt_messages = LLMNodeChatModelMessage(
role=PromptMessageRole.SYSTEM, text=QUESTION_CLASSIFIER_SYSTEM_PROMPT.format(histories=memory_str) role=PromptMessageRole.SYSTEM, text=QUESTION_CLASSIFIER_SYSTEM_PROMPT.format(
histories=memory_str)
) )
prompt_messages.append(system_prompt_messages) prompt_messages.append(system_prompt_messages)
user_prompt_message_1 = LLMNodeChatModelMessage( user_prompt_message_1 = LLMNodeChatModelMessage(
@ -311,4 +321,5 @@ class QuestionClassifierNode(LLMNode):
) )
else: else:
raise InvalidModelTypeError(f"Model mode {model_mode} not support.") raise InvalidModelTypeError(
f"Model mode {model_mode} not support.")

View File

@ -68,7 +68,8 @@ def test_executor_with_json_body_and_object_variable():
system_variables={}, system_variables={},
user_inputs={}, user_inputs={},
) )
variable_pool.add(["pre_node_id", "object"], {"name": "John Doe", "age": 30, "email": "john@example.com"}) variable_pool.add(["pre_node_id", "object"], {
"name": "John Doe", "age": 30, "email": "john@example.com"})
# Prepare the node data # Prepare the node data
node_data = HttpRequestNodeData( node_data = HttpRequestNodeData(
@ -102,7 +103,8 @@ def test_executor_with_json_body_and_object_variable():
assert executor.url == "https://api.example.com/data" assert executor.url == "https://api.example.com/data"
assert executor.headers == {"Content-Type": "application/json"} assert executor.headers == {"Content-Type": "application/json"}
assert executor.params == {} assert executor.params == {}
assert executor.json == {"name": "John Doe", "age": 30, "email": "john@example.com"} assert executor.json == {"name": "John Doe",
"age": 30, "email": "john@example.com"}
assert executor.data is None assert executor.data is None
assert executor.files is None assert executor.files is None
assert executor.content is None assert executor.content is None
@ -123,7 +125,8 @@ def test_executor_with_json_body_and_nested_object_variable():
system_variables={}, system_variables={},
user_inputs={}, user_inputs={},
) )
variable_pool.add(["pre_node_id", "object"], {"name": "John Doe", "age": 30, "email": "john@example.com"}) variable_pool.add(["pre_node_id", "object"], {
"name": "John Doe", "age": 30, "email": "john@example.com"})
# Prepare the node data # Prepare the node data
node_data = HttpRequestNodeData( node_data = HttpRequestNodeData(
@ -157,7 +160,8 @@ def test_executor_with_json_body_and_nested_object_variable():
assert executor.url == "https://api.example.com/data" assert executor.url == "https://api.example.com/data"
assert executor.headers == {"Content-Type": "application/json"} assert executor.headers == {"Content-Type": "application/json"}
assert executor.params == {} assert executor.params == {}
assert executor.json == {"object": {"name": "John Doe", "age": 30, "email": "john@example.com"}} assert executor.json == {"object": {
"name": "John Doe", "age": 30, "email": "john@example.com"}}
assert executor.data is None assert executor.data is None
assert executor.files is None assert executor.files is None
assert executor.content is None assert executor.content is None

View File

@ -23,7 +23,8 @@ def test_plain_text_to_dict():
assert _plain_text_to_dict("aa\n cc:") == {"aa": "", "cc": ""} assert _plain_text_to_dict("aa\n cc:") == {"aa": "", "cc": ""}
assert _plain_text_to_dict("aa:bb\n cc:dd") == {"aa": "bb", "cc": "dd"} assert _plain_text_to_dict("aa:bb\n cc:dd") == {"aa": "bb", "cc": "dd"}
assert _plain_text_to_dict("aa:bb\n cc:dd\n") == {"aa": "bb", "cc": "dd"} assert _plain_text_to_dict("aa:bb\n cc:dd\n") == {"aa": "bb", "cc": "dd"}
assert _plain_text_to_dict("aa:bb\n\n cc : dd\n\n") == {"aa": "bb", "cc": "dd"} assert _plain_text_to_dict("aa:bb\n\n cc : dd\n\n") == {
"aa": "bb", "cc": "dd"}
def test_http_request_node_binary_file(monkeypatch): def test_http_request_node_binary_file(monkeypatch):
@ -189,7 +190,8 @@ def test_http_request_node_form_with_file(monkeypatch):
def attr_checker(*args, **kwargs): def attr_checker(*args, **kwargs):
assert kwargs["data"] == {"name": "test"} assert kwargs["data"] == {"name": "test"}
assert kwargs["files"] == {"file": (None, b"test", "application/octet-stream")} assert kwargs["files"] == {
"file": (None, b"test", "application/octet-stream")}
return httpx.Response(200, content=b"") return httpx.Response(200, content=b"")
monkeypatch.setattr( monkeypatch.setattr(

View File

@ -318,6 +318,8 @@ services:
environment: environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-} CONSOLE_API_URL: ${CONSOLE_API_URL:-}
APP_API_URL: ${APP_API_URL:-} APP_API_URL: ${APP_API_URL:-}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-}
MARKETPLACE_URL: ${MARKETPLACE_URL:-}
SENTRY_DSN: ${WEB_SENTRY_DSN:-} SENTRY_DSN: ${WEB_SENTRY_DSN:-}
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}

View File

@ -1,5 +0,0 @@
{
"presets": [
"@babel/preset-env"
]
}

View File

@ -10,6 +10,10 @@ NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api
# console or api domain. # console or api domain.
# example: http://udify.app/api # example: http://udify.app/api
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
# The APIFREX for MARKETPLACE
NEXT_PUBLIC_MARKETPLACE_API_PREFIX=http://localhost:5002/api
# The URL for MARKETPLACE
NEXT_PUBLIC_MARKETPLACE_URL_PREFIX=
# SENTRY # SENTRY
NEXT_PUBLIC_SENTRY_DSN= NEXT_PUBLIC_SENTRY_DSN=
@ -25,3 +29,6 @@ NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS=60000
# CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP # CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
NEXT_PUBLIC_CSP_WHITELIST= NEXT_PUBLIC_CSP_WHITELIST=
# Github Access Token, used for invoking Github API
NEXT_PUBLIC_GITHUB_ACCESS_TOKEN=

View File

@ -1,7 +0,0 @@
/**/node_modules/*
node_modules/
dist/
build/
out/
.next/

View File

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

@ -44,10 +44,9 @@ package-lock.json
.pnp.cjs .pnp.cjs
.pnp.loader.mjs .pnp.loader.mjs
.yarn/ .yarn/
.yarnrc.yml
# pmpm
pnpm-lock.yaml
.favorites.json .favorites.json
# storybook
/storybook-static
*storybook.log *storybook.log

View File

@ -1,6 +1,3 @@
#!/usr/bin/env bash
. "$(dirname -- "$0")/_/husky.sh"
# get the list of modified files # get the list of modified files
files=$(git diff --cached --name-only) files=$(git diff --cached --name-only)
@ -50,7 +47,7 @@ fi
if $web_modified; then if $web_modified; then
echo "Running ESLint on web module" echo "Running ESLint on web module"
cd ./web || exit 1 cd ./web || exit 1
npx lint-staged lint-staged
echo "Running unit tests check" echo "Running unit tests check"
modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true) modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true)
@ -63,7 +60,7 @@ if $web_modified; then
# check if the test file exists # check if the test file exists
if [ -f "../$test_file" ]; then if [ -f "../$test_file" ]; then
echo "Detected changes in $file, running corresponding unit tests..." echo "Detected changes in $file, running corresponding unit tests..."
npm run test "../$test_file" pnpm run test "../$test_file"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Unit tests failed. Please fix the errors before committing." echo "Unit tests failed. Please fix the errors before committing."

View File

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import type { Preview } from '@storybook/react' import type { Preview } from '@storybook/react'
import { withThemeByDataAttribute } from '@storybook/addon-themes'; import { withThemeByDataAttribute } from '@storybook/addon-themes'
import I18nServer from '../app/components/i18n-server' import I18nServer from '../app/components/i18n-server'
import '../app/styles/globals.css' import '../app/styles/globals.css'
@ -16,12 +16,12 @@ export const decorators = [
defaultTheme: 'light', defaultTheme: 'light',
attributeName: 'data-theme', attributeName: 'data-theme',
}), }),
Story => { (Story) => {
return <I18nServer> return <I18nServer>
<Story /> <Story />
</I18nServer> </I18nServer>
} },
]; ]
const preview: Preview = { const preview: Preview = {
parameters: { parameters: {

View File

@ -21,5 +21,6 @@
"editor.defaultFormatter": "vscode.json-language-features" "editor.defaultFormatter": "vscode.json-language-features"
}, },
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true "typescript.enablePromptUseWorkspaceTsdk": true,
"npm.packageManager": "pnpm"
} }

View File

@ -6,6 +6,9 @@ LABEL maintainer="takatost@gmail.com"
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories # RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add --no-cache tzdata RUN apk add --no-cache tzdata
RUN npm install -g pnpm@9.12.2
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
# install packages # install packages
@ -14,12 +17,12 @@ FROM base AS packages
WORKDIR /app/web WORKDIR /app/web
COPY package.json . COPY package.json .
COPY yarn.lock . COPY pnpm-lock.yaml .
# if you located in China, you can use taobao registry to speed up # if you located in China, you can use taobao registry to speed up
# RUN yarn install --frozen-lockfile --registry https://registry.npmmirror.com/ # RUN pnpm install --frozen-lockfile --registry https://registry.npmmirror.com/
RUN yarn install --frozen-lockfile RUN pnpm install --frozen-lockfile
# build resources # build resources
FROM base AS builder FROM base AS builder
@ -27,7 +30,7 @@ WORKDIR /app/web
COPY --from=packages /app/web/ . COPY --from=packages /app/web/ .
COPY . . COPY . .
RUN yarn build RUN pnpm build
# production stage # production stage
@ -38,6 +41,8 @@ ENV EDITION=SELF_HOSTED
ENV DEPLOY_ENV=PRODUCTION ENV DEPLOY_ENV=PRODUCTION
ENV CONSOLE_API_URL=http://127.0.0.1:5001 ENV CONSOLE_API_URL=http://127.0.0.1:5001
ENV APP_API_URL=http://127.0.0.1:5001 ENV APP_API_URL=http://127.0.0.1:5001
ENV MARKETPLACE_API_URL=http://127.0.0.1:5001
ENV MARKETPLACE_URL=http://127.0.0.1:5001
ENV PORT=3000 ENV PORT=3000
ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_TELEMETRY_DISABLED=1
@ -57,8 +62,7 @@ COPY docker/entrypoint.sh ./entrypoint.sh
# global runtime packages # global runtime packages
RUN yarn global add pm2 \ RUN pnpm add -g pm2 \
&& yarn cache clean \
&& mkdir /.pm2 \ && mkdir /.pm2 \
&& chown -R 1001:0 /.pm2 /app/web \ && chown -R 1001:0 /.pm2 /app/web \
&& chmod -R g=u /.pm2 /app/web && chmod -R g=u /.pm2 /app/web

View File

@ -6,14 +6,12 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next
### Run by source code ### Run by source code
To start the web frontend service, you will need [Node.js v18.x (LTS)](https://nodejs.org/en) and [NPM version 8.x.x](https://www.npmjs.com/) or [Yarn](https://yarnpkg.com/). To start the web frontend service, you will need [Node.js v18.x (LTS)](https://nodejs.org/en) and [pnpm version 9.12.2](https://pnpm.io).
First, install the dependencies: First, install the dependencies:
```bash ```bash
npm install pnpm install
# or
yarn install --frozen-lockfile
``` ```
Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements: Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements:
@ -43,9 +41,7 @@ NEXT_PUBLIC_SENTRY_DSN=
Finally, run the development server: Finally, run the development server:
```bash ```bash
npm run dev pnpm run dev
# or
yarn dev
``` ```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
@ -59,19 +55,19 @@ You can start editing the file under folder `app`. The page auto-updates as you
First, build the app for production: First, build the app for production:
```bash ```bash
npm run build pnpm run build
``` ```
Then, start the server: Then, start the server:
```bash ```bash
npm run start pnpm run start
``` ```
If you want to customize the host and port: If you want to customize the host and port:
```bash ```bash
npm run start --port=3001 --host=0.0.0.0 pnpm run start --port=3001 --host=0.0.0.0
``` ```
## Storybook ## Storybook
@ -81,7 +77,7 @@ This project uses [Storybook](https://storybook.js.org/) for UI component develo
To start the storybook server, run: To start the storybook server, run:
```bash ```bash
yarn storybook pnpm storybook
``` ```
Open [http://localhost:6006](http://localhost:6006) with your browser to see the result. Open [http://localhost:6006](http://localhost:6006) with your browser to see the result.
@ -99,7 +95,7 @@ You can create a test file with a suffix of `.spec` beside the file that to be t
Run test: Run test:
```bash ```bash
npm run test pnpm run test
``` ```
If you are not familiar with writing tests, here is some code to refer to: If you are not familiar with writing tests, here is some code to refer to:

View File

@ -2,7 +2,7 @@ import React from 'react'
import Main from '@/app/components/app/log-annotation' import Main from '@/app/components/app/log-annotation'
import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type' import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
export type IProps = { export interface IProps {
params: { appId: string } params: { appId: string }
} }

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { type Locale } from '@/i18n' import type { Locale } from '@/i18n'
import DevelopMain from '@/app/components/develop' import DevelopMain from '@/app/components/develop'
export type IDevelopProps = { export type IDevelopProps = {

View File

@ -4,7 +4,7 @@ import React from 'react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import Input from '@/app/components/base/input' import Input from '@/app/components/base/input'
type Props = { interface Props {
className?: string className?: string
label: string label: string
labelClassName?: string labelClassName?: string

View File

@ -8,12 +8,11 @@ import { useBoolean } from 'ahooks'
import { import {
Cog8ToothIcon, Cog8ToothIcon,
// CommandLineIcon, // CommandLineIcon,
Squares2X2Icon,
// eslint-disable-next-line sort-imports
PuzzlePieceIcon,
DocumentTextIcon, DocumentTextIcon,
PaperClipIcon, PaperClipIcon,
PuzzlePieceIcon,
QuestionMarkCircleIcon, QuestionMarkCircleIcon,
Squares2X2Icon,
} from '@heroicons/react/24/outline' } from '@heroicons/react/24/outline'
import { import {
Cog8ToothIcon as Cog8ToothSolidIcon, Cog8ToothIcon as Cog8ToothSolidIcon,

View File

@ -5,7 +5,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useDebounceFn } from 'ahooks' import { useDebounceFn } from 'ahooks'
import useSWR from 'swr'
// Components // Components
import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel' import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel'
@ -28,6 +27,7 @@ import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
import { useStore as useTagStore } from '@/app/components/base/tag-management/store' import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
import { useAppContext } from '@/context/app-context' import { useAppContext } from '@/context/app-context'
import { useExternalApiPanel } from '@/context/external-api-panel-context' import { useExternalApiPanel } from '@/context/external-api-panel-context'
import { useQuery } from '@tanstack/react-query'
const Container = () => { const Container = () => {
const { t } = useTranslation() const { t } = useTranslation()
@ -47,7 +47,13 @@ const Container = () => {
defaultTab: 'dataset', defaultTab: 'dataset',
}) })
const containerRef = useRef<HTMLDivElement>(null) const containerRef = useRef<HTMLDivElement>(null)
const { data } = useSWR(activeTab === 'dataset' ? null : '/datasets/api-base-info', fetchDatasetApiBaseUrl) const { data } = useQuery(
{
queryKey: ['datasetApiBaseInfo', activeTab],
queryFn: () => fetchDatasetApiBaseUrl('/datasets/api-base-info'),
enabled: activeTab !== 'dataset',
},
)
const [keywords, setKeywords] = useState('') const [keywords, setKeywords] = useState('')
const [searchKeywords, setSearchKeywords] = useState('') const [searchKeywords, setSearchKeywords] = useState('')

View File

@ -8,12 +8,14 @@ import Header from '@/app/components/header'
import { EventEmitterContextProvider } from '@/context/event-emitter' import { EventEmitterContextProvider } from '@/context/event-emitter'
import { ProviderContextProvider } from '@/context/provider-context' import { ProviderContextProvider } from '@/context/provider-context'
import { ModalContextProvider } from '@/context/modal-context' import { ModalContextProvider } from '@/context/modal-context'
import { TanstackQueryIniter } from '@/context/query-client'
const Layout = ({ children }: { children: ReactNode }) => { const Layout = ({ children }: { children: ReactNode }) => {
return ( return (
<> <>
<GA gaType={GaType.admin} /> <GA gaType={GaType.admin} />
<SwrInitor> <SwrInitor>
<TanstackQueryIniter>
<AppContextProvider> <AppContextProvider>
<EventEmitterContextProvider> <EventEmitterContextProvider>
<ProviderContextProvider> <ProviderContextProvider>
@ -26,6 +28,7 @@ const Layout = ({ children }: { children: ReactNode }) => {
</ProviderContextProvider> </ProviderContextProvider>
</EventEmitterContextProvider> </EventEmitterContextProvider>
</AppContextProvider> </AppContextProvider>
</TanstackQueryIniter>
</SwrInitor> </SwrInitor>
</> </>
) )

View File

@ -0,0 +1,18 @@
import PluginPage from '@/app/components/plugins/plugin-page'
import PluginsPanel from '@/app/components/plugins/plugin-page/plugins-panel'
import Marketplace from '@/app/components/plugins/marketplace'
const PluginList = async () => {
return (
<PluginPage
plugins={<PluginsPanel />}
marketplace={<Marketplace />}
/>
)
}
export const metadata = {
title: 'Plugins - Dify',
}
export default PluginList

View File

@ -0,0 +1,14 @@
'use server'
import { revalidatePath } from 'next/cache'
// Server Actions
export async function handleDelete() {
// revalidatePath only invalidates the cache when the included path is next visited.
revalidatePath('/')
}
export async function fetchPluginDetail(org: string, name: string) {
// Fetch plugin detail TODO
return { org, name }
}

View File

@ -0,0 +1,98 @@
'use client'
import Card from '@/app/components/plugins/card'
import { customTool, extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock'
// import PluginItem from '@/app/components/plugins/plugin-item'
import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
// import ProviderCard from '@/app/components/plugins/provider-card'
import Badge from '@/app/components/base/badge'
import InstallBundle from '@/app/components/plugins/install-plugin/install-bundle'
const PluginList = () => {
const pluginList = [toolNotion, extensionDallE, modelGPT4, customTool]
return (
<div className='pb-3 bg-white'>
<InstallBundle onClose={() => { }} fromDSLPayload={[
// {
// type: 'marketplace',
// value: {
// plugin_unique_identifier: 'langgenius/google:0.0.2@dcb354c9d0fee60e6e9c9eb996e1e485bbef343ba8cd545c0cfb3ec80970f6f1',
// },
// },
{
type: 'github',
value: {
repo: 'YIXIAO0/test',
version: '1.11.5',
package: 'test.difypkg',
github_plugin_unique_identifier: 'yixiao0/test:0.0.1@3592166c87afcf944b4f13f27467a5c8f9e00bd349cb42033a072734a37431b4',
},
},
// {
// type: 'marketplace',
// value: {
// plugin_unique_identifier: 'langgenius/openai:0.0.1@f88fdb98d104466db16a425bfe3af8c1bcad45047a40fb802d98a989ac57a5a3',
// },
// },
]} />
<div className='mx-3 '>
{/* <h2 className='my-3'>Dify Plugin list</h2> */}
{/* <div className='grid grid-cols-2 gap-3'>
{pluginList.map((plugin, index) => (
<PluginItem
key={index}
payload={plugin as any}
onDelete={handleDelete}
/>
))}
</div> */}
<h2 className='my-3'>Install Plugin / Package under bundle</h2>
<div className='w-[512px] rounded-2xl bg-background-section-burn p-2'>
<Card
payload={toolNotion as any}
descriptionLineRows={1}
titleLeft={
<Badge className='ml-1' text={toolNotion.version} />
}
/>
</div>
{/* <h3 className='my-1'>Installed</h3>
<div className='w-[512px] rounded-2xl bg-background-section-burn p-2'>
<Card
payload={toolNotion as any}
descriptionLineRows={1}
installed
/>
</div> */}
{/* <h3 className='my-1'>Install model provide</h3>
<div className='grid grid-cols-2 gap-3'>
{pluginList.map((plugin, index) => (
<ProviderCard key={index} payload={plugin as any} />
))}
</div> */}
<div className='my-3 h-[px] bg-gray-50'></div>
<h2 className='my-3'>Marketplace Plugin list</h2>
<div className='grid grid-cols-4 gap-3'>
{pluginList.map((plugin, index) => (
<Card
key={index}
payload={plugin as any}
footer={
<CardMoreInfo downloadCount={index % 2 === 0 ? 1234 : 6} tags={index % 2 === 0 ? ['Search', 'Tag that has very very long name', 'Productivity', 'Tag2'] : []} />
}
/>
))}
</div>
</div>
</div>
)
}
// export const metadata = {
// title: 'Plugins - Card',
// }
export default PluginList

View File

@ -0,0 +1,20 @@
'use client'
import { useBoolean } from 'ahooks'
import UpdatePlugin from '@/app/components/plugins/update-plugin'
const Page = () => {
const [isShowUpdateModal, {
setTrue: showUpdateModal,
setFalse: hideUpdateModal,
}] = useBoolean(false)
return (
<div>
<div onClick={showUpdateModal}>Show Upgrade</div>
{isShowUpdateModal && (
<UpdatePlugin onHide={hideUpdateModal} />
)}
</div>
)
}
export default Page

View File

@ -0,0 +1,22 @@
'use client'
import React from 'react'
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
const ToolsPicker = () => {
const [show, setShow] = React.useState(true)
return (
<div className=' mt-10 ml-10'>
<ToolPicker
trigger={<div className='inline-block w-[70px]'>Click me</div>}
isShow={show}
onShowChange={setShow}
disabled={false}
supportAddCustomTool={true}
onSelect={() => { }}
/>
</div>
)
}
export default ToolsPicker

View File

@ -0,0 +1,67 @@
'use client'
import { toolNeko } from '@/app/components/plugins/card/card-mock'
import { PluginSource } from '@/app/components/plugins/types'
import { useModalContext } from '@/context/modal-context'
import React from 'react'
const UpdatePlugin = () => {
const { setShowUpdatePluginModal } = useModalContext()
const handleUpdateFromMarketPlace = () => {
setShowUpdatePluginModal({
payload: {
type: PluginSource.marketplace,
marketPlace: {
originalPackageInfo: {
id: 'langgenius/neko:0.0.1@9e57d693739287c0efdc96847d7ed959ca93f70aa704471f2eb7ed3313821824',
payload: toolNeko as any,
},
targetPackageInfo: {
id: 'target_xxx',
version: '1.2.3',
},
},
},
onCancelCallback: () => {
console.log('canceled')
},
onSaveCallback: () => {
console.log('saved')
},
})
}
const handleUpdateFromGithub = () => {
setShowUpdatePluginModal({
payload: {
type: PluginSource.github,
github: {
originalPackageInfo: {
id: '111',
repo: 'aaa/bbb',
version: 'xxx',
url: 'aaa/bbb',
currVersion: '1.2.3',
currPackage: 'pack1',
} as any,
},
},
onCancelCallback: () => {
console.log('canceled')
},
onSaveCallback: () => {
console.log('saved')
},
})
}
return (
<div>
<div></div>
<div className='flex space-x-1'>
<div className='underline cursor-pointer' onClick={handleUpdateFromMarketPlace}> Marketplace</div>
<div className='underline cursor-pointer' onClick={handleUpdateFromGithub}> GitHub</div>
</div>
</div>
)
}
export default React.memo(UpdatePlugin)

View File

@ -8,7 +8,7 @@ import { logout } from '@/service/common'
import { useAppContext } from '@/context/app-context' import { useAppContext } from '@/context/app-context'
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general' import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
export type IAppSelector = { export interface IAppSelector {
isMobile: boolean isMobile: boolean
} }

View File

@ -6,11 +6,11 @@ import useSWR from 'swr'
import Input from '@/app/components/base/input' import Input from '@/app/components/base/input'
import { fetchAnnotationsCount } from '@/service/log' import { fetchAnnotationsCount } from '@/service/log'
export type QueryParam = { export interface QueryParam {
keyword?: string keyword?: string
} }
type IFilterProps = { interface IFilterProps {
appId: string appId: string
queryParams: QueryParam queryParams: QueryParam
setQueryParams: (v: QueryParam) => void setQueryParams: (v: QueryParam) => void

View File

@ -27,7 +27,7 @@ import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general' import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
import type { App } from '@/types/app' import type { App } from '@/types/app'
type Props = { interface Props {
appDetail: App appDetail: App
} }

View File

@ -9,7 +9,7 @@ import RemoveAnnotationConfirmModal from './remove-annotation-confirm-modal'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import useTimestamp from '@/hooks/use-timestamp' import useTimestamp from '@/hooks/use-timestamp'
type Props = { interface Props {
list: AnnotationItem[] list: AnnotationItem[]
onRemove: (id: string) => void onRemove: (id: string) => void
onView: (item: AnnotationItem) => void onView: (item: AnnotationItem) => void

View File

@ -23,7 +23,7 @@ const FeaturePanel: FC<IFeaturePanelProps> = ({
children, children,
}) => { }) => {
return ( return (
<div className={cn('rounded-xl border-t-[0.5px] border-l-[0.5px] bg-background-section-burn pb-3', noBodySpacing && '!pb-0', className)}> <div className={cn('rounded-xl border-t-[0.5px] border-l-[0.5px] bg-background-section-burn pb-3', noBodySpacing && 'pb-0', className)}>
{/* Header */} {/* Header */}
<div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')}> <div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')}>
<div className='flex justify-between items-center h-8'> <div className='flex justify-between items-center h-8'>

View File

@ -9,7 +9,7 @@ import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid
import I18n from '@/context/i18n' import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language' import { LanguagesSupported } from '@/i18n/language'
type Props = { interface Props {
showWarning: boolean showWarning: boolean
onShowEditModal: () => void onShowEditModal: () => void
} }

View File

@ -9,7 +9,7 @@ import ConfirmAddVar from './confirm-add-var'
import s from './style.module.css' import s from './style.module.css'
import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap' import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { type PromptVariable } from '@/models/debug' import type { PromptVariable } from '@/models/debug'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import type { CompletionParams } from '@/types/app' import type { CompletionParams } from '@/types/app'
import { AppType } from '@/types/app' import { AppType } from '@/types/app'

View File

@ -3,7 +3,7 @@ import type { FC } from 'react'
import React from 'react' import React from 'react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type Props = { interface Props {
className?: string className?: string
title: string title: string
children: JSX.Element children: JSX.Element

View File

@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
const TEXT_MAX_LENGTH = 256 const TEXT_MAX_LENGTH = 256
export type IConfigModalProps = { export interface IConfigModalProps {
isCreate?: boolean isCreate?: boolean
payload?: InputVar payload?: InputVar
isShow: boolean isShow: boolean

View File

@ -3,7 +3,7 @@ import type { FC } from 'react'
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import Input from '@/app/components/base/input' import Input from '@/app/components/base/input'
export type IConfigStringProps = { export interface IConfigStringProps {
value: number | undefined value: number | undefined
maxLength: number maxLength: number
modelId: string modelId: string
@ -28,7 +28,7 @@ const ConfigString: FC<IConfigStringProps> = ({
min={1} min={1}
value={value || ''} value={value || ''}
onChange={(e) => { onChange={(e) => {
let value = parseInt(e.target.value, 10) let value = Number.parseInt(e.target.value, 10)
if (value > maxLength) if (value > maxLength)
value = maxLength value = maxLength

View File

@ -3,7 +3,6 @@ import type { FC } from 'react'
import React, { useState } from 'react' import React, { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
import type { Timeout } from 'ahooks/lib/useRequest/src/types'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import produce from 'immer' import produce from 'immer'
import { import {
@ -34,7 +33,7 @@ import { InputVarType } from '@/app/components/workflow/types'
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL' export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
type ExternalDataToolParams = { interface ExternalDataToolParams {
key: string key: string
type: string type: string
index: number index: number
@ -44,13 +43,13 @@ type ExternalDataToolParams = {
icon_background?: string icon_background?: string
} }
export type IConfigVarProps = { export interface IConfigVarProps {
promptVariables: PromptVariable[] promptVariables: PromptVariable[]
readonly?: boolean readonly?: boolean
onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
} }
let conflictTimer: Timeout let conflictTimer: number
const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => { const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => {
const { t } = useTranslation() const { t } = useTranslation()
@ -107,7 +106,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
onPromptVariablesChange?.(newPromptVariables) onPromptVariablesChange?.(newPromptVariables)
} }
const updatePromptKey = (index: number, newKey: string) => { const updatePromptKey = (index: number, newKey: string) => {
clearTimeout(conflictTimer) window.clearTimeout(conflictTimer)
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true) const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
if (!isValid) { if (!isValid) {
Toast.notify({ Toast.notify({
@ -127,7 +126,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
return item return item
}) })
conflictTimer = setTimeout(() => { conflictTimer = window.setTimeout(() => {
const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim()) const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim())
if (isKeyExists) { if (isKeyExists) {
Toast.notify({ Toast.notify({

View File

@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import type { InputVarType } from '@/app/components/workflow/types' import type { InputVarType } from '@/app/components/workflow/types'
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon' import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
export type ISelectTypeItemProps = { export interface ISelectTypeItemProps {
type: InputVarType type: InputVarType
selected: boolean selected: boolean
onClick: () => void onClick: () => void

View File

@ -1,21 +1,25 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React, { useState } from 'react' import React, { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import copy from 'copy-to-clipboard'
import produce from 'immer' import produce from 'immer'
import { import {
RiDeleteBinLine, RiDeleteBinLine,
RiEqualizer2Line,
RiHammerFill, RiHammerFill,
RiInformation2Line,
} from '@remixicon/react' } from '@remixicon/react'
import { useFormattingChangedDispatcher } from '../../../debug/hooks' import { useFormattingChangedDispatcher } from '../../../debug/hooks'
import SettingBuiltInTool from './setting-built-in-tool' import SettingBuiltInTool from './setting-built-in-tool'
import cn from '@/utils/classnames'
import Panel from '@/app/components/app/configuration/base/feature-panel' import Panel from '@/app/components/app/configuration/base/feature-panel'
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
import OperationBtn from '@/app/components/app/configuration/base/operation-btn' import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
import AppIcon from '@/app/components/base/app-icon' import AppIcon from '@/app/components/base/app-icon'
import Button from '@/app/components/base/button'
import Indicator from '@/app/components/header/indicator'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import Toast from '@/app/components/base/toast'
import ConfigContext from '@/context/debug-configuration' import ConfigContext from '@/context/debug-configuration'
import type { AgentTool } from '@/types/app' import type { AgentTool } from '@/types/app'
import { type Collection, CollectionType } from '@/app/components/tools/types' import { type Collection, CollectionType } from '@/app/components/tools/types'
@ -23,7 +27,12 @@ import { MAX_TOOLS_NUM } from '@/config'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other' import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
import AddToolModal from '@/app/components/tools/add-tool-modal' // import AddToolModal from '@/app/components/tools/add-tool-modal'
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
import { updateBuiltInToolCredential } from '@/service/tools'
import cn from '@/utils/classnames'
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null
const AgentTools: FC = () => { const AgentTools: FC = () => {
@ -33,7 +42,13 @@ const AgentTools: FC = () => {
const formattingChangedDispatcher = useFormattingChangedDispatcher() const formattingChangedDispatcher = useFormattingChangedDispatcher()
const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null) const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null)
const currentCollection = useMemo(() => {
if (!currentTool) return null
const collection = collectionList.find(collection => collection.id === currentTool?.provider_id && collection.type === currentTool?.provider_type)
return collection
}, [currentTool, collectionList])
const [isShowSettingTool, setIsShowSettingTool] = useState(false) const [isShowSettingTool, setIsShowSettingTool] = useState(false)
const [isShowSettingAuth, setShowSettingAuth] = useState(false)
const tools = (modelConfig?.agentConfig?.tools as AgentTool[] || []).map((item) => { const tools = (modelConfig?.agentConfig?.tools as AgentTool[] || []).map((item) => {
const collection = collectionList.find(collection => collection.id === item.provider_id && collection.type === item.provider_type) const collection = collectionList.find(collection => collection.id === item.provider_id && collection.type === item.provider_type)
const icon = collection?.icon const icon = collection?.icon
@ -55,10 +70,39 @@ const AgentTools: FC = () => {
formattingChangedDispatcher() formattingChangedDispatcher()
} }
const handleToolAuthSetting = (value: any) => {
const newModelConfig = produce(modelConfig, (draft) => {
const tool = (draft.agentConfig.tools).find((item: any) => item.provider_id === value?.collection?.id && item.tool_name === value?.tool_name)
if (tool)
(tool as AgentTool).notAuthor = false
})
setModelConfig(newModelConfig)
setIsShowSettingTool(false)
formattingChangedDispatcher()
}
const [isDeleting, setIsDeleting] = useState<number>(-1)
const handleSelectTool = (tool: ToolDefaultValue) => {
const newModelConfig = produce(modelConfig, (draft) => {
draft.agentConfig.tools.push({
provider_id: tool.provider_id,
provider_type: tool.provider_type as CollectionType,
provider_name: tool.provider_name,
tool_name: tool.tool_name,
tool_label: tool.tool_label,
tool_parameters: tool.params,
notAuthor: !tool.is_team_authorization,
enabled: true,
})
})
setModelConfig(newModelConfig)
}
return ( return (
<> <>
<Panel <Panel
className="mt-2" className={cn('mt-2', tools.length === 0 && 'pb-2')}
noBodySpacing={tools.length === 0} noBodySpacing={tools.length === 0}
headerIcon={ headerIcon={
<RiHammerFill className='w-4 h-4 text-primary-500' /> <RiHammerFill className='w-4 h-4 text-primary-500' />
@ -81,7 +125,14 @@ const AgentTools: FC = () => {
{tools.length < MAX_TOOLS_NUM && ( {tools.length < MAX_TOOLS_NUM && (
<> <>
<div className='ml-3 mr-1 h-3.5 w-px bg-gray-200'></div> <div className='ml-3 mr-1 h-3.5 w-px bg-gray-200'></div>
<OperationBtn type="add" onClick={() => setIsShowChooseTool(true)} /> <ToolPicker
trigger={<OperationBtn type="add" />}
isShow={isShowChooseTool}
onShowChange={setIsShowChooseTool}
disabled={false}
supportAddCustomTool
onSelect={handleSelectTool}
/>
</> </>
)} )}
</div> </div>
@ -90,72 +141,78 @@ const AgentTools: FC = () => {
<div className='grid gap-1 grid-cols-1 2xl:grid-cols-2 items-center flex-wrap justify-between'> <div className='grid gap-1 grid-cols-1 2xl:grid-cols-2 items-center flex-wrap justify-between'>
{tools.map((item: AgentTool & { icon: any; collection?: Collection }, index) => ( {tools.map((item: AgentTool & { icon: any; collection?: Collection }, index) => (
<div key={index} <div key={index}
className={cn((item.isDeleted || item.notAuthor) ? 'bg-white/50' : 'bg-white', (item.enabled && !item.isDeleted && !item.notAuthor) && 'shadow-xs', index > 1 && 'mt-1', 'group relative flex justify-between items-center last-of-type:mb-0 pl-2.5 py-2 pr-3 w-full rounded-lg border-[0.5px] border-gray-200 ')} className={cn(
'group relative flex justify-between items-center last-of-type:mb-0 p-1.5 pr-2 w-full bg-components-panel-on-panel-item-bg rounded-lg border-[0.5px] border-components-panel-border-subtle shadow-xs hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm cursor',
isDeleting === index && 'hover:bg-state-destructive-hover border-state-destructive-border',
)}
> >
<div className='grow w-0 flex items-center'> <div className='grow w-0 flex items-center'>
{(item.isDeleted || item.notAuthor) {item.isDeleted && <DefaultToolIcon className='w-5 h-5' />}
? ( {!item.isDeleted && (
<DefaultToolIcon className='w-6 h-6' /> <div className={cn((item.notAuthor || !item.enabled) && 'opacity-50')}>
) {typeof item.icon === 'string' && <div className='w-5 h-5 bg-cover bg-center rounded-md' style={{ backgroundImage: `url(${item.icon})` }} />}
: ( {typeof item.icon !== 'string' && <AppIcon className='rounded-md' size='xs' icon={item.icon?.content} background={item.icon?.background} />}
typeof item.icon === 'string' </div>
? ( )}
<div <div
className='w-6 h-6 bg-cover bg-center rounded-md' className={cn(
style={{ 'grow w-0 ml-1.5 flex items-center system-xs-regular truncate',
backgroundImage: `url(${item.icon})`, item.isDeleted ? 'line-through' : '',
}} (item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '',
></div> )}
)
: (
<AppIcon
className='rounded-md'
size='tiny'
icon={item.icon?.content}
background={item.icon?.background}
/>
))}
<div
className={cn((item.isDeleted || item.notAuthor) ? 'line-through opacity-50' : '', 'grow w-0 ml-2 leading-[18px] text-[13px] font-medium text-gray-800 truncate')}
> >
<span className='text-gray-800 pr-2'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span> <span className='text-text-secondary pr-1.5'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span>
<span className='text-text-tertiary'>{item.tool_name}</span>
{!item.isDeleted && (
<Tooltip <Tooltip
popupContent={t('tools.toolNameUsageTip')} needsDelay
popupContent={
<div className='w-[180px]'>
<div className='mb-1.5 text-text-secondary'>{item.tool_name}</div>
<div className='mb-1.5 text-text-tertiary'>{t('tools.toolNameUsageTip')}</div>
<div className='text-text-accent cursor-pointer' onClick={() => copy(item.tool_name)}>{t('tools.copyToolName')}</div>
</div>
}
> >
<span className='text-gray-500'>{item.tool_name}</span> <div className='w-4 h-4'>
<div className='hidden group-hover:inline-block ml-0.5'>
<RiInformation2Line className='w-4 h-4 text-text-tertiary' />
</div>
</div>
</Tooltip> </Tooltip>
)}
</div> </div>
</div> </div>
<div className='shrink-0 ml-1 flex items-center'> <div className='shrink-0 ml-1 flex items-center'>
{(item.isDeleted || item.notAuthor) {item.isDeleted && (
? ( <div className='flex items-center mr-2'>
<div className='flex items-center'>
<Tooltip <Tooltip
popupContent={t(`tools.${item.isDeleted ? 'toolRemoved' : 'notAuthorized'}`)} popupContent={t('tools.toolRemoved')}
needsDelay needsDelay
> >
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { <div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer'>
if (item.notAuthor)
setIsShowChooseTool(true)
}}>
<AlertTriangle className='w-4 h-4 text-[#F79009]' /> <AlertTriangle className='w-4 h-4 text-[#F79009]' />
</div> </div>
</Tooltip> </Tooltip>
<div
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
onClick={() => {
const newModelConfig = produce(modelConfig, (draft) => { const newModelConfig = produce(modelConfig, (draft) => {
draft.agentConfig.tools.splice(index, 1) draft.agentConfig.tools.splice(index, 1)
}) })
setModelConfig(newModelConfig) setModelConfig(newModelConfig)
formattingChangedDispatcher() formattingChangedDispatcher()
}}> }}
<RiDeleteBinLine className='w-4 h-4 text-gray-500' /> onMouseOver={() => setIsDeleting(index)}
onMouseLeave={() => setIsDeleting(-1)}
>
<RiDeleteBinLine className='w-4 h-4' />
</div> </div>
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
</div> </div>
) )}
: ( {!item.isDeleted && (
<div className='hidden group-hover:flex items-center'> <div className='hidden group-hover:flex items-center gap-1 mr-2'>
{!item.notAuthor && (
<Tooltip <Tooltip
popupContent={t('tools.setBuiltInTools.infoAndSetting')} popupContent={t('tools.setBuiltInTools.infoAndSetting')}
needsDelay needsDelay
@ -164,26 +221,31 @@ const AgentTools: FC = () => {
setCurrentTool(item) setCurrentTool(item)
setIsShowSettingTool(true) setIsShowSettingTool(true)
}}> }}>
<InfoCircle className='w-4 h-4 text-gray-500' /> <RiEqualizer2Line className='w-4 h-4 text-text-tertiary' />
</div> </div>
</Tooltip> </Tooltip>
)}
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => { <div
className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
onClick={() => {
const newModelConfig = produce(modelConfig, (draft) => { const newModelConfig = produce(modelConfig, (draft) => {
draft.agentConfig.tools.splice(index, 1) draft.agentConfig.tools.splice(index, 1)
}) })
setModelConfig(newModelConfig) setModelConfig(newModelConfig)
formattingChangedDispatcher() formattingChangedDispatcher()
}}> }}
<RiDeleteBinLine className='w-4 h-4 text-gray-500' /> onMouseOver={() => setIsDeleting(index)}
onMouseLeave={() => setIsDeleting(-1)}
>
<RiDeleteBinLine className='w-4 h-4' />
</div> </div>
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
</div> </div>
)} )}
<div className={cn((item.isDeleted || item.notAuthor) && 'opacity-50')}> <div className={cn(item.isDeleted && 'opacity-50')}>
{!item.notAuthor && (
<Switch <Switch
defaultValue={(item.isDeleted || item.notAuthor) ? false : item.enabled} defaultValue={item.isDeleted ? false : item.enabled}
disabled={(item.isDeleted || item.notAuthor)} disabled={item.isDeleted}
size='md' size='md'
onChange={(enabled) => { onChange={(enabled) => {
const newModelConfig = produce(modelConfig, (draft) => { const newModelConfig = produce(modelConfig, (draft) => {
@ -192,17 +254,23 @@ const AgentTools: FC = () => {
setModelConfig(newModelConfig) setModelConfig(newModelConfig)
formattingChangedDispatcher() formattingChangedDispatcher()
}} /> }} />
)}
{item.notAuthor && (
<Button variant='secondary' size='small' onClick={() => {
setCurrentTool(item)
setShowSettingAuth(true)
}}>
{t('tools.notAuthorized')}
<Indicator className='ml-2' color='orange' />
</Button>
)}
</div> </div>
</div> </div>
</div> </div>
))} ))}
</div > </div >
</Panel > </Panel >
{isShowChooseTool && ( {isShowSettingTool && (
<AddToolModal onHide={() => setIsShowChooseTool(false)} />
)}
{
isShowSettingTool && (
<SettingBuiltInTool <SettingBuiltInTool
toolName={currentTool?.tool_name as string} toolName={currentTool?.tool_name as string}
setting={currentTool?.tool_parameters as any} setting={currentTool?.tool_parameters as any}
@ -211,8 +279,23 @@ const AgentTools: FC = () => {
isModel={currentTool?.collection?.type === CollectionType.model} isModel={currentTool?.collection?.type === CollectionType.model}
onSave={handleToolSettingChange} onSave={handleToolSettingChange}
onHide={() => setIsShowSettingTool(false)} onHide={() => setIsShowSettingTool(false)}
/>) />
} )}
{isShowSettingAuth && (
<ConfigCredential
collection={currentCollection as any}
onCancel={() => setShowSettingAuth(false)}
onSaved={async (value) => {
await updateBuiltInToolCredential((currentCollection as any).name, value)
Toast.notify({
type: 'success',
message: t('common.api.actionSuccess'),
})
handleToolAuthSetting(currentTool as any)
setShowSettingAuth(false)
}}
/>
)}
</> </>
) )
} }

View File

@ -3,21 +3,30 @@ import type { FC } from 'react'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import cn from '@/utils/classnames' import {
import Drawer from '@/app/components/base/drawer-plus' RiArrowLeftLine,
RiCloseLine,
} from '@remixicon/react'
import Drawer from '@/app/components/base/drawer'
import Loading from '@/app/components/base/loading'
import ActionButton from '@/app/components/base/action-button'
import Icon from '@/app/components/plugins/card/base/card-icon'
import OrgInfo from '@/app/components/plugins/card/base/org-info'
import Description from '@/app/components/plugins/card/base/description'
import TabSlider from '@/app/components/base/tab-slider-plain'
import Button from '@/app/components/base/button'
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form' import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
import { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema' import { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
import type { Collection, Tool } from '@/app/components/tools/types' import type { Collection, Tool } from '@/app/components/tools/types'
import { CollectionType } from '@/app/components/tools/types' import { CollectionType } from '@/app/components/tools/types'
import { fetchBuiltInToolList, fetchCustomToolList, fetchModelToolList, fetchWorkflowToolList } from '@/service/tools' import { fetchBuiltInToolList, fetchCustomToolList, fetchModelToolList, fetchWorkflowToolList } from '@/service/tools'
import I18n from '@/context/i18n' import I18n from '@/context/i18n'
import Button from '@/app/components/base/button'
import Loading from '@/app/components/base/loading'
import { DiagonalDividingLine } from '@/app/components/base/icons/src/public/common'
import { getLanguage } from '@/i18n/language' import { getLanguage } from '@/i18n/language'
import AppIcon from '@/app/components/base/app-icon' import cn from '@/utils/classnames'
type Props = { interface Props {
showBackButton?: boolean
collection: Collection collection: Collection
isBuiltIn?: boolean isBuiltIn?: boolean
isModel?: boolean isModel?: boolean
@ -29,6 +38,7 @@ type Props = {
} }
const SettingBuiltInTool: FC<Props> = ({ const SettingBuiltInTool: FC<Props> = ({
showBackButton = false,
collection, collection,
isBuiltIn = true, isBuiltIn = true,
isModel = true, isModel = true,
@ -97,39 +107,26 @@ const SettingBuiltInTool: FC<Props> = ({
})() })()
const infoUI = ( const infoUI = (
<div className='pt-2'> <div className=''>
<div className='leading-5 text-sm font-medium text-gray-900'>
{t('tools.setBuiltInTools.toolDescription')}
</div>
<div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'>
{currTool?.description[language]}
</div>
{infoSchemas.length > 0 && ( {infoSchemas.length > 0 && (
<div className='mt-6'> <div className='py-2 space-y-1'>
<div className='flex items-center mb-4 leading-[18px] text-xs font-semibold text-gray-500 uppercase'>
<div className='mr-3'>{t('tools.setBuiltInTools.parameters')}</div>
<div className='grow w-0 h-px bg-[#f3f4f6]'></div>
</div>
<div className='space-y-4'>
{infoSchemas.map((item: any, index) => ( {infoSchemas.map((item: any, index) => (
<div key={index}> <div key={index} className='py-1'>
<div className='flex items-center space-x-2 leading-[18px]'> <div className='flex items-center gap-2'>
<div className='text-[13px] font-semibold text-gray-900'>{item.label[language]}</div> <div className='text-text-secondary code-sm-semibold'>{item.label[language]}</div>
<div className='text-xs font-medium text-gray-500'>{item.type === 'number-input' ? t('tools.setBuiltInTools.number') : t('tools.setBuiltInTools.string')}</div> <div className='text-text-tertiary system-xs-regular'>{item.type === 'number-input' ? t('tools.setBuiltInTools.number') : t('tools.setBuiltInTools.string')}</div>
{item.required && ( {item.required && (
<div className='text-xs font-medium text-[#EC4A0A]'>{t('tools.setBuiltInTools.required')}</div> <div className='text-text-warning-secondary system-xs-medium'>{t('tools.setBuiltInTools.required')}</div>
)} )}
</div> </div>
{item.human_description && ( {item.human_description && (
<div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'> <div className='mt-0.5 text-text-tertiary system-xs-regular'>
{item.human_description?.[language]} {item.human_description?.[language]}
</div> </div>
)} )}
</div> </div>
))} ))}
</div> </div>
</div>
)} )}
</div> </div>
) )
@ -149,61 +146,68 @@ const SettingBuiltInTool: FC<Props> = ({
return ( return (
<Drawer <Drawer
isShow isOpen
onHide={onHide} clickOutsideNotOpen={false}
title={( onClose={onHide}
<div className='flex items-center'> footer={null}
{typeof collection.icon === 'string' mask={false}
? ( positionCenter={false}
panelClassname={cn('justify-start mt-[64px] mr-2 mb-2 !w-[420px] !max-w-[420px] !p-0 !bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadow-xl')}
>
<>
{isLoading && <Loading type='app' />}
{!isLoading && (
<>
{/* header */}
<div className='relative p-4 pb-3 border-b border-divider-subtle'>
<div className='absolute top-3 right-3'>
<ActionButton onClick={onHide}>
<RiCloseLine className='w-4 h-4' />
</ActionButton>
</div>
{showBackButton && (
<div <div
className='w-6 h-6 bg-cover bg-center rounded-md flex-shrink-0' className='mb-2 flex items-center gap-1 text-text-accent-secondary system-xs-semibold-uppercase cursor-pointer'
style={{ onClick={onHide}
backgroundImage: `url(${collection.icon})`, >
}} <RiArrowLeftLine className='w-4 h-4' />
></div> BACK
) </div>
: ( )}
<AppIcon <div className='flex items-center gap-1'>
className='rounded-md' <Icon size='tiny' className='w-6 h-6' src={collection.icon} />
size='tiny' <OrgInfo
icon={(collection.icon as any)?.content} packageNameClassName='w-auto'
background={(collection.icon as any)?.background} orgName={collection.author}
packageName={collection.name}
/> />
</div>
<div className='mt-1 text-text-primary system-md-semibold'>{currTool?.label[language]}</div>
{!!currTool?.description[language] && (
<Description className='mt-3' text={currTool.description[language]} descriptionLineRows={2}></Description>
)} )}
<div className='ml-2 leading-6 text-base font-semibold text-gray-900'>{currTool?.label[language]}</div>
{(hasSetting && !readonly) && (<>
<DiagonalDividingLine className='mx-4' />
<div className='flex space-x-6'>
<div
className={cn(isInfoActive ? 'text-gray-900 font-semibold' : 'font-normal text-gray-600 cursor-pointer', 'relative text-base')}
onClick={() => setCurrType('info')}
>
{t('tools.setBuiltInTools.info')}
{isInfoActive && <div className='absolute left-0 bottom-[-16px] w-full h-0.5 bg-primary-600'></div>}
</div>
<div className={cn(!isInfoActive ? 'text-gray-900 font-semibold' : 'font-normal text-gray-600 cursor-pointer', 'relative text-base ')}
onClick={() => setCurrType('setting')}
>
{t('tools.setBuiltInTools.setting')}
{!isInfoActive && <div className='absolute left-0 bottom-[-16px] w-full h-0.5 bg-primary-600'></div>}
</div>
</div>
</>)}
</div> </div>
{/* form */}
<div className='h-full'>
<div className='flex flex-col h-full'>
{(hasSetting && !readonly) ? (
<TabSlider
className='shrink-0 mt-1 px-4'
itemClassName='py-3'
noBorderBottom
value={currType}
onChange={(value) => {
setCurrType(value)
}}
options={[
{ value: 'info', text: t('tools.setBuiltInTools.parameters')! },
{ value: 'setting', text: t('tools.setBuiltInTools.setting')! },
]}
/>
) : (
<div className='p-4 pb-1 text-text-primary system-sm-semibold-uppercase'>{t('tools.setBuiltInTools.parameters')}</div>
)} )}
panelClassName='mt-[65px] !w-[405px]' <div className='grow h-0 overflow-y-auto px-4'>
maxWidthClassName='!max-w-[405px]'
height='calc(100vh - 65px)'
headerClassName='!border-b-black/5'
body={
<div className='h-full pt-3'>
{isLoading
? <div className='flex h-full items-center'>
<Loading type='app' />
</div>
: (<div className='flex flex-col h-full'>
<div className='grow h-0 overflow-y-auto px-6'>
{isInfoActive ? infoUI : settingUI} {isInfoActive ? infoUI : settingUI}
</div> </div>
{!readonly && !isInfoActive && ( {!readonly && !isInfoActive && (
@ -212,12 +216,12 @@ const SettingBuiltInTool: FC<Props> = ({
<Button className='flex items-center h-8 !px-3 !text-[13px] font-medium' variant='primary' disabled={!isValid} onClick={() => onSave?.(addDefaultValue(tempSetting, formSchemas))}>{t('common.operation.save')}</Button> <Button className='flex items-center h-8 !px-3 !text-[13px] font-medium' variant='primary' disabled={!isValid} onClick={() => onSave?.(addDefaultValue(tempSetting, formSchemas))}>{t('common.operation.save')}</Button>
</div> </div>
)} )}
</div>)}
</div> </div>
} </div>
isShowMask={false} </>
clickOutsideNotOpen={false} )}
/> </>
</Drawer>
) )
} }
export default React.memo(SettingBuiltInTool) export default React.memo(SettingBuiltInTool)

View File

@ -38,7 +38,7 @@ import ModelName from '@/app/components/header/account-setting/model-provider-pa
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
export type IGetAutomaticResProps = { export interface IGetAutomaticResProps {
mode: AppType mode: AppType
model: Model model: Model
isShow: boolean isShow: boolean

View File

@ -11,7 +11,7 @@ import AgentTools from './agent/agent-tools'
import ConfigContext from '@/context/debug-configuration' import ConfigContext from '@/context/debug-configuration'
import ConfigPrompt from '@/app/components/app/configuration/config-prompt' import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
import ConfigVar from '@/app/components/app/configuration/config-var' import ConfigVar from '@/app/components/app/configuration/config-var'
import { type ModelConfig, type PromptVariable } from '@/models/debug' import type { ModelConfig, PromptVariable } from '@/models/debug'
import type { AppType } from '@/types/app' import type { AppType } from '@/types/app'
import { ModelModeType } from '@/types/app' import { ModelModeType } from '@/types/app'

View File

@ -25,7 +25,7 @@ import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowled
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
type Props = { interface Props {
datasetConfigs: DatasetConfigs datasetConfigs: DatasetConfigs
onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
isInWorkflow?: boolean isInWorkflow?: boolean

View File

@ -19,7 +19,7 @@ import {
getMultipleRetrievalConfig, getMultipleRetrievalConfig,
} from '@/app/components/workflow/nodes/knowledge-retrieval/utils' } from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
type ParamsConfigProps = { interface ParamsConfigProps {
disabled?: boolean disabled?: boolean
selectedDatasets: DataSet[] selectedDatasets: DataSet[]
} }

View File

@ -33,7 +33,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
import { fetchMembers } from '@/service/common' import { fetchMembers } from '@/service/common'
import type { Member } from '@/models/common' import type { Member } from '@/models/common'
type SettingsModalProps = { interface SettingsModalProps {
currentDataset: DataSet currentDataset: DataSet
onCancel: () => void onCancel: () => void
onSave: (newDataset: DataSet) => void onSave: (newDataset: DataSet) => void

View File

@ -30,7 +30,7 @@ import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-
import { useFeatures } from '@/app/components/base/features/hooks' import { useFeatures } from '@/app/components/base/features/hooks'
import type { InputForm } from '@/app/components/base/chat/chat/type' import type { InputForm } from '@/app/components/base/chat/chat/type'
type ChatItemProps = { interface ChatItemProps {
modelAndParameter: ModelAndParameter modelAndParameter: ModelAndParameter
} }
const ChatItem: FC<ChatItemProps> = ({ const ChatItem: FC<ChatItemProps> = ({

View File

@ -1,7 +1,7 @@
'use client' 'use client'
import { createContext, useContext } from 'use-context-selector'
import type { ModelAndParameter } from '../types' import type { ModelAndParameter } from '../types'
import { createSelectorCtx } from '@/utils/context'
export type DebugWithMultipleModelContextType = { export type DebugWithMultipleModelContextType = {
multipleModelConfigs: ModelAndParameter[] multipleModelConfigs: ModelAndParameter[]
@ -9,13 +9,9 @@ export type DebugWithMultipleModelContextType = {
onDebugWithMultipleModelChange: (singleModelConfig: ModelAndParameter) => void onDebugWithMultipleModelChange: (singleModelConfig: ModelAndParameter) => void
checkCanSend?: () => boolean checkCanSend?: () => boolean
} }
const DebugWithMultipleModelContext = createContext<DebugWithMultipleModelContextType>({ const [,useDebugWithMultipleModelContext, DebugWithMultipleModelContext] = createSelectorCtx<DebugWithMultipleModelContextType>()
multipleModelConfigs: [],
onMultipleModelConfigsChange: () => {},
onDebugWithMultipleModelChange: () => {},
})
export const useDebugWithMultipleModelContext = () => useContext(DebugWithMultipleModelContext) export { useDebugWithMultipleModelContext }
type DebugWithMultipleModelContextProviderProps = { type DebugWithMultipleModelContextProviderProps = {
children: React.ReactNode children: React.ReactNode

View File

@ -15,7 +15,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import { useFeatures } from '@/app/components/base/features/hooks' import { useFeatures } from '@/app/components/base/features/hooks'
type TextGenerationItemProps = { interface TextGenerationItemProps {
modelAndParameter: ModelAndParameter modelAndParameter: ModelAndParameter
} }
const TextGenerationItem: FC<TextGenerationItemProps> = ({ const TextGenerationItem: FC<TextGenerationItemProps> = ({

View File

@ -27,10 +27,10 @@ import { useFeatures } from '@/app/components/base/features/hooks'
import { getLastAnswer } from '@/app/components/base/chat/utils' import { getLastAnswer } from '@/app/components/base/chat/utils'
import type { InputForm } from '@/app/components/base/chat/chat/type' import type { InputForm } from '@/app/components/base/chat/chat/type'
type DebugWithSingleModelProps = { interface DebugWithSingleModelProps {
checkCanSend?: () => boolean checkCanSend?: () => boolean
} }
export type DebugWithSingleModelRefType = { export interface DebugWithSingleModelRefType {
handleRestart: () => void handleRestart: () => void
} }
const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({ const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({

View File

@ -48,7 +48,7 @@ import PromptLogModal from '@/app/components/base/prompt-log-modal'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks' import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
type IDebug = { interface IDebug {
isAPIKeySet: boolean isAPIKeySet: boolean
onSetting: () => void onSetting: () => void
inputs: Inputs inputs: Inputs

View File

@ -59,7 +59,7 @@ import {
useTextGenerationCurrentProviderAndModelAndModelList, useTextGenerationCurrentProviderAndModelAndModelList,
} from '@/app/components/header/account-setting/model-provider-page/hooks' } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { fetchCollectionList } from '@/service/tools' import { fetchCollectionList } from '@/service/tools'
import { type Collection } from '@/app/components/tools/types' import type { Collection } from '@/app/components/tools/types'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import { import {
getMultipleRetrievalConfig, getMultipleRetrievalConfig,
@ -71,6 +71,7 @@ import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
import { SupportUploadFileTypes } from '@/app/components/workflow/types' import { SupportUploadFileTypes } from '@/app/components/workflow/types'
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel' import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
import { fetchFileUploadConfig } from '@/service/common' import { fetchFileUploadConfig } from '@/service/common'
import { correctProvider } from '@/utils'
type PublishConfig = { type PublishConfig = {
modelConfig: ModelConfig modelConfig: ModelConfig
@ -156,7 +157,7 @@ const Configuration: FC = () => {
const setCompletionParams = (value: FormValue) => { const setCompletionParams = (value: FormValue) => {
const params = { ...value } const params = { ...value }
// eslint-disable-next-line @typescript-eslint/no-use-before-define // eslint-disable-next-line ts/no-use-before-define
if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) { if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
params.stop = getTempStop() params.stop = getTempStop()
setTempStop([]) setTempStop([])
@ -165,7 +166,7 @@ const Configuration: FC = () => {
} }
const [modelConfig, doSetModelConfig] = useState<ModelConfig>({ const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
provider: 'openai', provider: 'langgenius/openai/openai',
model_id: 'gpt-3.5-turbo', model_id: 'gpt-3.5-turbo',
mode: ModelModeType.unset, mode: ModelModeType.unset,
configs: { configs: {
@ -188,7 +189,7 @@ const Configuration: FC = () => {
const isAgent = mode === 'agent-chat' const isAgent = mode === 'agent-chat'
const isOpenAI = modelConfig.provider === 'openai' const isOpenAI = modelConfig.provider === 'langgenius/openai/openai'
const [collectionList, setCollectionList] = useState<Collection[]>([]) const [collectionList, setCollectionList] = useState<Collection[]>([])
useEffect(() => { useEffect(() => {
@ -357,7 +358,7 @@ const Configuration: FC = () => {
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true) const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
const setPromptMode = async (mode: PromptMode) => { const setPromptMode = async (mode: PromptMode) => {
if (mode === PromptMode.advanced) { if (mode === PromptMode.advanced) {
// eslint-disable-next-line @typescript-eslint/no-use-before-define // eslint-disable-next-line ts/no-use-before-define
await migrateToDefaultPrompt() await migrateToDefaultPrompt()
setCanReturnToSimpleMode(true) setCanReturnToSimpleMode(true)
} }
@ -542,8 +543,19 @@ const Configuration: FC = () => {
if (modelConfig.retriever_resource) if (modelConfig.retriever_resource)
setCitationConfig(modelConfig.retriever_resource) setCitationConfig(modelConfig.retriever_resource)
if (modelConfig.annotation_reply) if (modelConfig.annotation_reply) {
setAnnotationConfig(modelConfig.annotation_reply, true) let annotationConfig = modelConfig.annotation_reply
if (modelConfig.annotation_reply.enabled) {
annotationConfig = {
...modelConfig.annotation_reply,
embedding_model: {
...modelConfig.annotation_reply.embedding_model,
embedding_provider_name: correctProvider(modelConfig.annotation_reply.embedding_model.embedding_provider_name),
},
}
}
setAnnotationConfig(annotationConfig, true)
}
if (modelConfig.sensitive_word_avoidance) if (modelConfig.sensitive_word_avoidance)
setModerationConfig(modelConfig.sensitive_word_avoidance) setModerationConfig(modelConfig.sensitive_word_avoidance)
@ -553,7 +565,7 @@ const Configuration: FC = () => {
const config = { const config = {
modelConfig: { modelConfig: {
provider: model.provider, provider: correctProvider(model.provider),
model_id: model.name, model_id: model.name,
mode: model.mode, mode: model.mode,
configs: { configs: {
@ -595,7 +607,6 @@ const Configuration: FC = () => {
annotation_reply: modelConfig.annotation_reply, annotation_reply: modelConfig.annotation_reply,
external_data_tools: modelConfig.external_data_tools, external_data_tools: modelConfig.external_data_tools,
dataSets: datasets || [], dataSets: datasets || [],
// eslint-disable-next-line multiline-ternary
agentConfig: res.mode === 'agent-chat' ? { agentConfig: res.mode === 'agent-chat' ? {
max_iteration: DEFAULT_AGENT_SETTING.max_iteration, max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
...modelConfig.agent_mode, ...modelConfig.agent_mode,
@ -608,6 +619,10 @@ const Configuration: FC = () => {
...tool, ...tool,
isDeleted: res.deleted_tools?.includes(tool.tool_name), isDeleted: res.deleted_tools?.includes(tool.tool_name),
notAuthor: collectionList.find(c => tool.provider_id === c.id)?.is_team_authorization === false, notAuthor: collectionList.find(c => tool.provider_id === c.id)?.is_team_authorization === false,
...(tool.provider_type === 'builtin' ? {
provider_id: correctProvider(tool.provider_name),
provider_name: correctProvider(tool.provider_name),
} : {}),
} }
}), }),
} : DEFAULT_AGENT_SETTING, } : DEFAULT_AGENT_SETTING,
@ -625,6 +640,12 @@ const Configuration: FC = () => {
retrieval_model: RETRIEVE_TYPE.multiWay, retrieval_model: RETRIEVE_TYPE.multiWay,
...modelConfig.dataset_configs, ...modelConfig.dataset_configs,
...retrievalConfig, ...retrievalConfig,
...(retrievalConfig.reranking_model ? {
reranking_model: {
...retrievalConfig.reranking_model,
reranking_provider_name: correctProvider(modelConfig.dataset_configs.reranking_model.reranking_provider_name),
},
} : {}),
}) })
setHasFetchedDetail(true) setHasFetchedDetail(true)
}) })

View File

@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
export type IPromptValuePanelProps = { export interface IPromptValuePanelProps {
appType: AppType appType: AppType
onSend?: () => void onSend?: () => void
inputs: Inputs inputs: Inputs

View File

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

View File

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

View File

@ -21,13 +21,13 @@ import { useToastContext } from '@/app/components/base/toast'
import AppIcon from '@/app/components/base/app-icon' import AppIcon from '@/app/components/base/app-icon'
const systemTypes = ['api'] const systemTypes = ['api']
type ExternalDataToolModalProps = { interface ExternalDataToolModalProps {
data: ExternalDataTool data: ExternalDataTool
onCancel: () => void onCancel: () => void
onSave: (externalDataTool: ExternalDataTool) => void onSave: (externalDataTool: ExternalDataTool) => void
onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
} }
type Provider = { interface Provider {
key: string key: string
name: string name: string
form_schema?: CodeBasedExtensionItem['form_schema'] form_schema?: CodeBasedExtensionItem['form_schema']

View File

@ -29,7 +29,7 @@ import Tooltip from '@/app/components/base/tooltip'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { getRedirection } from '@/utils/app-redirection' import { getRedirection } from '@/utils/app-redirection'
type CreateAppDialogProps = { interface CreateAppDialogProps {
show: boolean show: boolean
onSuccess: () => void onSuccess: () => void
onClose: () => void onClose: () => void

View File

@ -21,6 +21,7 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { getRedirection } from '@/utils/app-redirection' import { getRedirection } from '@/utils/app-redirection'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { useMutationCheckDependenciesBeforeImportDSL } from '@/service/use-plugins'
type CreateFromDSLModalProps = { type CreateFromDSLModalProps = {
show: boolean show: boolean
@ -43,6 +44,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
const [fileContent, setFileContent] = useState<string>() const [fileContent, setFileContent] = useState<string>()
const [currentTab, setCurrentTab] = useState(activeTab) const [currentTab, setCurrentTab] = useState(activeTab)
const [dslUrlValue, setDslUrlValue] = useState(dslUrl) const [dslUrlValue, setDslUrlValue] = useState(dslUrl)
const { mutateAsync } = useMutationCheckDependenciesBeforeImportDSL()
const readFile = (file: File) => { const readFile = (file: File) => {
const reader = new FileReader() const reader = new FileReader()
@ -78,11 +80,21 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
let app let app
if (currentTab === CreateFromDSLModalTab.FROM_FILE) { if (currentTab === CreateFromDSLModalTab.FROM_FILE) {
const leakedData = await mutateAsync({ dslString: fileContent })
if (leakedData?.leaked.length) {
isCreatingRef.current = false
return
}
app = await importApp({ app = await importApp({
data: fileContent || '', data: fileContent || '',
}) })
} }
if (currentTab === CreateFromDSLModalTab.FROM_URL) { if (currentTab === CreateFromDSLModalTab.FROM_URL) {
const leakedData = await mutateAsync({ url: dslUrlValue })
if (leakedData?.leaked.length) {
isCreatingRef.current = false
return
}
app = await importAppFromUrl({ app = await importAppFromUrl({
url: dslUrlValue || '', url: dslUrlValue || '',
}) })

View File

@ -13,7 +13,7 @@ import { useProviderContext } from '@/context/provider-context'
import AppsFull from '@/app/components/billing/apps-full-in-dialog' import AppsFull from '@/app/components/billing/apps-full-in-dialog'
import type { AppIconType } from '@/types/app' import type { AppIconType } from '@/types/app'
export type DuplicateAppModalProps = { export interface DuplicateAppModalProps {
appName: string appName: string
icon_type: AppIconType | null icon_type: AppIconType | null
icon: string icon: string

View File

@ -12,7 +12,7 @@ import { PageType } from '@/app/components/base/features/new-feature-panel/annot
import TabSlider from '@/app/components/base/tab-slider-plain' import TabSlider from '@/app/components/base/tab-slider-plain'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
type Props = { interface Props {
pageType: PageType pageType: PageType
} }

View File

@ -27,7 +27,7 @@ export const TIME_PERIOD_LIST = [
{ value: 'all', name: 'allTime' }, { value: 'all', name: 'allTime' },
] ]
type IFilterProps = { interface IFilterProps {
isChatMode?: boolean isChatMode?: boolean
appId: string appId: string
queryParams: QueryParam queryParams: QueryParam

View File

@ -17,11 +17,11 @@ import Loading from '@/app/components/base/loading'
import { fetchChatConversations, fetchCompletionConversations } from '@/service/log' import { fetchChatConversations, fetchCompletionConversations } from '@/service/log'
import { APP_PAGE_LIMIT } from '@/config' import { APP_PAGE_LIMIT } from '@/config'
import type { App, AppMode } from '@/types/app' import type { App, AppMode } from '@/types/app'
export type ILogsProps = { export interface ILogsProps {
appDetail: App appDetail: App
} }
export type QueryParam = { export interface QueryParam {
period?: number | string period?: number | string
annotation_status?: string annotation_status?: string
keyword?: string keyword?: string

View File

@ -13,7 +13,7 @@ import InfiniteScroll from 'react-infinite-scroll-component'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc' import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone' import timezone from 'dayjs/plugin/timezone'
import { createContext, useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import { useShallow } from 'zustand/react/shallow' import { useShallow } from 'zustand/react/shallow'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import type { ChatItemInTree } from '../../base/chat/types' import type { ChatItemInTree } from '../../base/chat/types'
@ -44,6 +44,8 @@ import Tooltip from '@/app/components/base/tooltip'
import { CopyIcon } from '@/app/components/base/copy-icon' import { CopyIcon } from '@/app/components/base/copy-icon'
import { buildChatItemTree, getThreadMessages } from '@/app/components/base/chat/utils' import { buildChatItemTree, getThreadMessages } from '@/app/components/base/chat/utils'
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils' import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
import { correctProvider } from '@/utils'
import { createSelectorCtx } from '@/utils/context'
dayjs.extend(utc) dayjs.extend(utc)
dayjs.extend(timezone) dayjs.extend(timezone)
@ -61,7 +63,7 @@ type IDrawerContext = {
appDetail?: App appDetail?: App
} }
const DrawerContext = createContext<IDrawerContext>({} as IDrawerContext) const [,, DrawerContext] = createSelectorCtx<IDrawerContext>()
/** /**
* Icon component with numbers * Icon component with numbers
@ -324,7 +326,7 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
})?.name ?? 'custom' })?.name ?? 'custom'
const modelName = (detail.model_config as any).model?.name const modelName = (detail.model_config as any).model?.name
const provideName = (detail.model_config as any).model?.provider as any const provideName = correctProvider((detail.model_config as any).model?.provider as any)
const { const {
currentModel, currentModel,
currentProvider, currentProvider,

View File

@ -20,7 +20,7 @@ const Progress: FC<IProgressProps> = ({
className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')} className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')}
style={{ width: `${value}%` }} style={{ width: `${value}%` }}
/> />
{Array(10).fill(0).map((i, k) => ( {Array.from({ length: 10 }).fill(0).map((i, k) => (
<div key={k} className={s['bar-item']} /> <div key={k} className={s['bar-item']} />
))} ))}
</div> </div>

View File

@ -243,7 +243,7 @@ const Chart: React.FC<IChartProps> = ({
? '' ? ''
: <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'> : <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'>
<span className='ml-1 text-gray-500'>(</span> <span className='ml-1 text-gray-500'>(</span>
<span className='text-orange-400'>~{sum(statistics.map(item => parseFloat(get(item, 'total_price', '0')))).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 4 })}</span> <span className='text-orange-400'>~{sum(statistics.map(item => Number.parseFloat(get(item, 'total_price', '0')))).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 4 })}</span>
<span className='text-gray-500'>)</span> <span className='text-gray-500'>)</span>
</span></span>} </span></span>}
textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-gray-300' : ''}` }} /> textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-gray-300' : ''}` }} />

View File

@ -22,7 +22,7 @@ import AppContext, { useAppContext } from '@/context/app-context'
import type { AppIconSelection } from '@/app/components/base/app-icon-picker' import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
import AppIconPicker from '@/app/components/base/app-icon-picker' import AppIconPicker from '@/app/components/base/app-icon-picker'
export type ISettingsModalProps = { export interface ISettingsModalProps {
isChat: boolean isChat: boolean
appInfo: AppDetailResponse & Partial<AppSSO> appInfo: AppDetailResponse & Partial<AppSSO>
isShow: boolean isShow: boolean
@ -31,7 +31,7 @@ export type ISettingsModalProps = {
onSave?: (params: ConfigParams) => Promise<void> onSave?: (params: ConfigParams) => Promise<void>
} }
export type ConfigParams = { export interface ConfigParams {
title: string title: string
description: string description: string
default_language: string default_language: string

View File

@ -2,7 +2,7 @@ import { create } from 'zustand'
import type { App, AppSSO } from '@/types/app' import type { App, AppSSO } from '@/types/app'
import type { IChatItem } from '@/app/components/base/chat/chat/type' import type { IChatItem } from '@/app/components/base/chat/chat/type'
type State = { interface State {
appDetail?: App & Partial<AppSSO> appDetail?: App & Partial<AppSSO>
appSidebarExpand: string appSidebarExpand: string
currentLogItem?: IChatItem currentLogItem?: IChatItem
@ -13,7 +13,7 @@ type State = {
showAppConfigureFeaturesModal: boolean showAppConfigureFeaturesModal: boolean
} }
type Action = { interface Action {
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
setAppSiderbarExpand: (state: string) => void setAppSiderbarExpand: (state: string) => void
setCurrentLogItem: (item?: IChatItem) => void setCurrentLogItem: (item?: IChatItem) => void

View File

@ -25,7 +25,7 @@ import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/aler
import AppIcon from '@/app/components/base/app-icon' import AppIcon from '@/app/components/base/app-icon'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
type SwitchAppModalProps = { interface SwitchAppModalProps {
show: boolean show: boolean
appDetail: App appDetail: App
onSuccess?: () => void onSuccess?: () => void

View File

@ -33,7 +33,7 @@ import { useChatContext } from '@/app/components/base/chat/chat/context'
const MAX_DEPTH = 3 const MAX_DEPTH = 3
export type IGenerationItemProps = { export interface IGenerationItemProps {
isWorkflow?: boolean isWorkflow?: boolean
workflowProcessData?: WorkflowProcess workflowProcessData?: WorkflowProcess
className?: string className?: string

View File

@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
import { RiCloseLine } from '@remixicon/react' import { RiCloseLine } from '@remixicon/react'
import Run from '@/app/components/workflow/run' import Run from '@/app/components/workflow/run'
type ILogDetail = { interface ILogDetail {
runID: string runID: string
onClose: () => void onClose: () => void
} }

View File

@ -6,7 +6,7 @@ import type { QueryParam } from './index'
import Chip from '@/app/components/base/chip' import Chip from '@/app/components/base/chip'
import Input from '@/app/components/base/input' import Input from '@/app/components/base/input'
type IFilterProps = { interface IFilterProps {
queryParams: QueryParam queryParams: QueryParam
setQueryParams: (v: QueryParam) => void setQueryParams: (v: QueryParam) => void
} }

View File

@ -16,11 +16,11 @@ import { fetchWorkflowLogs } from '@/service/log'
import { APP_PAGE_LIMIT } from '@/config' import { APP_PAGE_LIMIT } from '@/config'
import type { App, AppMode } from '@/types/app' import type { App, AppMode } from '@/types/app'
export type ILogsProps = { export interface ILogsProps {
appDetail: App appDetail: App
} }
export type QueryParam = { export interface QueryParam {
status?: string status?: string
keyword?: string keyword?: string
} }

View File

@ -13,7 +13,7 @@ import Indicator from '@/app/components/header/indicator'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import useTimestamp from '@/hooks/use-timestamp' import useTimestamp from '@/hooks/use-timestamp'
type ILogs = { interface ILogs {
logs?: WorkflowLogsResponse logs?: WorkflowLogsResponse
appDetail?: App appDetail?: App
onRefresh: () => void onRefresh: () => void

View File

@ -2,9 +2,7 @@
@layer components { @layer components {
.action-btn { .action-btn {
@apply inline-flex justify-center items-center cursor-pointer text-text-tertiary @apply inline-flex justify-center items-center cursor-pointer text-text-tertiary hover:text-text-secondary hover:bg-state-base-hover
hover:text-text-secondary
hover:bg-state-base-hover
} }
.action-btn-disabled { .action-btn-disabled {
@ -29,21 +27,15 @@
} }
.action-btn.action-btn-active { .action-btn.action-btn-active {
@apply @apply text-text-accent bg-state-accent-active hover:bg-state-accent-active-alt
text-text-accent
bg-state-accent-active
hover:bg-state-accent-active-alt
} }
.action-btn.action-btn-disabled { .action-btn.action-btn-disabled {
@apply @apply text-text-disabled
text-text-disabled
} }
.action-btn.action-btn-destructive { .action-btn.action-btn-destructive {
@apply @apply text-text-destructive bg-state-destructive-hover
text-text-destructive
bg-state-destructive-hover
} }
} }

View File

@ -28,7 +28,7 @@ const actionButtonVariants = cva(
) )
export type ActionButtonProps = { export type ActionButtonProps = {
size?: 'xs' | 'm' | 'l' | 'xl' size?: 'xs' | 's' | 'm' | 'l' | 'xl'
state?: ActionButtonState state?: ActionButtonState
styleCss?: CSSProperties styleCss?: CSSProperties
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants> } & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>

View File

@ -15,7 +15,7 @@
} }
.appIcon.xs { .appIcon.xs {
@apply w-3 h-3 text-base; @apply w-5 h-5 text-base;
} }
.appIcon.rounded { .appIcon.rounded {

View File

@ -1,6 +1,6 @@
import AudioPlayer from '@/app/components/base/audio-btn/audio' import AudioPlayer from '@/app/components/base/audio-btn/audio'
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions // eslint-disable-next-line ts/consistent-type-definitions
interface AudioPlayerManager { interface AudioPlayerManager {
instance: AudioPlayerManager instance: AudioPlayerManager
} }
@ -12,6 +12,7 @@ export class AudioPlayerManager {
private audioPlayers: AudioPlayer | null = null private audioPlayers: AudioPlayer | null = null
private msgId: string | undefined private msgId: string | undefined
// eslint-disable-next-line
private constructor() { private constructor() {
} }

View File

@ -2,7 +2,7 @@ import Toast from '@/app/components/base/toast'
import { textToAudioStream } from '@/service/share' import { textToAudioStream } from '@/service/share'
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions // eslint-disable-next-line ts/consistent-type-definitions
interface Window { interface Window {
ManagedMediaSource: any ManagedMediaSource: any
} }

View File

@ -7,7 +7,7 @@ import Tooltip from '@/app/components/base/tooltip'
import Loading from '@/app/components/base/loading' import Loading from '@/app/components/base/loading'
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager' import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
type AudioBtnProps = { interface AudioBtnProps {
id?: string id?: string
voice?: string voice?: string
value?: string value?: string

View File

@ -2,15 +2,15 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
background-color: #ffffff; background-color: var(--color-components-chat-input-audio-bg-alt);
border-radius: 10px; border-radius: 10px;
padding: 8px; padding: 8px;
min-width: 240px; min-width: 240px;
max-width: 420px; max-width: 420px;
max-height: 40px; max-height: 40px;
backdrop-filter: blur(5px); backdrop-filter: blur(5px);
border: 1px solid rgba(16, 24, 40, 0.08); border: 1px solid var(--color-components-panel-border-subtle);
box-shadow: 0 1px 2px rgba(9, 9, 11, 0.05); box-shadow: 0 1px 2px var(--color-shadow-shadow-3);
gap: 8px; gap: 8px;
} }
@ -19,8 +19,8 @@
width: 16px; width: 16px;
height: 16px; height: 16px;
border-radius: 50%; border-radius: 50%;
background-color: #296DFF; background-color: var(--color-components-button-primary-bg);
color: white; color: var(--color-components-chat-input-audio-bg-alt);
border: none; border: none;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
@ -30,16 +30,15 @@
} }
.playButton:hover { .playButton:hover {
background-color: #3367d6; background-color: var(--color-components-button-primary-bg-hover);
} }
.playButton:disabled { .playButton:disabled {
background-color: #bdbdbf; background-color: var(--color-components-button-primary-bg-disabled);
} }
.audioControls { .audioControls {
flex-grow: 1; flex-grow: 1;
} }
.progressBarContainer { .progressBarContainer {
@ -76,8 +75,8 @@
.timeDisplay { .timeDisplay {
/* position: absolute; */ /* position: absolute; */
color: #296DFF; color: var(--color-text-accent-secondary);
border-radius: 2px; font-size: 12px;
order: 0; order: 0;
height: 100%; height: 100%;
width: 50px; width: 50px;
@ -97,7 +96,6 @@
} */ } */
.duration { .duration {
background-color: rgba(255, 255, 255, 0.8);
padding: 2px 4px; padding: 2px 4px;
border-radius: 10px; border-radius: 10px;
} }

View File

@ -55,7 +55,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
audio.load() audio.load()
// Delayed generation of waveform data // Delayed generation of waveform data
// eslint-disable-next-line @typescript-eslint/no-use-before-define // eslint-disable-next-line ts/no-use-before-define
const timer = setTimeout(() => generateWaveformData(src), 1000) const timer = setTimeout(() => generateWaveformData(src), 1000)
return () => { return () => {

View File

@ -49,4 +49,6 @@ const AutoHeightTextarea = forwardRef<HTMLTextAreaElement, AutoHeightTextareaPro
}, },
) )
AutoHeightTextarea.displayName = 'AutoHeightTextarea'
export default AutoHeightTextarea export default AutoHeightTextarea

View File

@ -5,22 +5,28 @@ type BadgeProps = {
className?: string className?: string
text: string text: string
uppercase?: boolean uppercase?: boolean
hasRedCornerMark?: boolean
} }
const Badge = ({ const Badge = ({
className, className,
text, text,
uppercase = true, uppercase = true,
hasRedCornerMark,
}: BadgeProps) => { }: BadgeProps) => {
return ( return (
<div <div
className={cn( className={cn(
'inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary', 'relative inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary',
uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium', uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium',
className, className,
)} )}
> >
{text} {text}
{hasRedCornerMark && (
<div className='absolute top-[-2px] right-[-2px] w-1.5 h-1.5 border border-components-badge-status-light-error-border-inner bg-components-badge-status-light-error-bg rounded-[2px] shadow-sm'>
</div>
)}
</div> </div>
) )
} }

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

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

View File

@ -4,7 +4,7 @@ import React from 'react'
import { RiAddLine } from '@remixicon/react' import { RiAddLine } from '@remixicon/react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type Props = { interface Props {
className?: string className?: string
onClick: () => void onClick: () => void
} }

View File

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import { memo } from 'react' import { memo } from 'react'
import Textarea from '@/app/components/base/textarea' import Textarea from '@/app/components/base/textarea'
type InputProps = { interface InputProps {
form: any form: any
value: string value: string
onChange: (variable: string, value: string) => void onChange: (variable: string, value: string) => void

View File

@ -1,7 +1,6 @@
'use client' 'use client'
import type { RefObject } from 'react' import type { RefObject } from 'react'
import { createContext, useContext } from 'use-context-selector'
import type { import type {
Callback, Callback,
ChatConfig, ChatConfig,
@ -15,6 +14,7 @@ import type {
AppMeta, AppMeta,
ConversationItem, ConversationItem,
} from '@/models/share' } from '@/models/share'
import { createSelectorCtx } from '@/utils/context'
export type ChatWithHistoryContextValue = { export type ChatWithHistoryContextValue = {
appInfoError?: any appInfoError?: any
@ -51,29 +51,4 @@ export type ChatWithHistoryContextValue = {
themeBuilder?: ThemeBuilder themeBuilder?: ThemeBuilder
} }
export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>({ export const [, useChatWithHistoryContext, ChatWithHistoryContext] = createSelectorCtx<ChatWithHistoryContextValue>()
currentConversationId: '',
appPrevChatList: [],
pinnedConversationList: [],
conversationList: [],
showConfigPanelBeforeChat: false,
newConversationInputs: {},
newConversationInputsRef: { current: {} },
handleNewConversationInputsChange: () => {},
inputsForms: [],
handleNewConversation: () => {},
handleStartChat: () => {},
handleChangeConversation: () => {},
handlePinConversation: () => {},
handleUnpinConversation: () => {},
handleDeleteConversation: () => {},
conversationRenaming: false,
handleRenameConversation: () => {},
handleNewConversationCompleted: () => {},
chatShouldReloadKey: '',
isMobile: false,
isInstalledApp: false,
handleFeedback: () => {},
currentChatInstanceRef: { current: { handleStop: () => {} } },
})
export const useChatWithHistoryContext = () => useContext(ChatWithHistoryContext)

View File

@ -20,7 +20,7 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { checkOrSetAccessToken } from '@/app/components/share/utils' import { checkOrSetAccessToken } from '@/app/components/share/utils'
import AppUnavailable from '@/app/components/base/app-unavailable' import AppUnavailable from '@/app/components/base/app-unavailable'
type ChatWithHistoryProps = { interface ChatWithHistoryProps {
className?: string className?: string
} }
const ChatWithHistory: FC<ChatWithHistoryProps> = ({ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
@ -99,7 +99,7 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
) )
} }
export type ChatWithHistoryWrapProps = { export interface ChatWithHistoryWrapProps {
installedAppInfo?: InstalledApp installedAppInfo?: InstalledApp
className?: string className?: string
} }

View File

@ -8,7 +8,7 @@ import Thought from '@/app/components/base/chat/chat/thought'
import { FileList } from '@/app/components/base/file-uploader' import { FileList } from '@/app/components/base/file-uploader'
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils' import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
type AgentContentProps = { interface AgentContentProps {
item: ChatItem item: ChatItem
responding?: boolean responding?: boolean
} }

View File

@ -4,7 +4,7 @@ import type { ChatItem } from '../../types'
import { Markdown } from '@/app/components/base/markdown' import { Markdown } from '@/app/components/base/markdown'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type BasicContentProps = { interface BasicContentProps {
item: ChatItem item: ChatItem
} }
const BasicContent: FC<BasicContentProps> = ({ const BasicContent: FC<BasicContentProps> = ({

View File

@ -23,7 +23,7 @@ import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { FileList } from '@/app/components/base/file-uploader' import { FileList } from '@/app/components/base/file-uploader'
type AnswerProps = { interface AnswerProps {
item: ChatItem item: ChatItem
question: string question: string
index: number index: number

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