From a84cb60728dcbf150c6845c7fc14ad48438f32e5 Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Tue, 11 Nov 2025 15:14:18 +0800 Subject: [PATCH 1/8] Fixes: Fixed model provider issues and improved some features - Removed the old login page - Updated model provider icons - Added RAPTOR modification range parameter --- web/public/iconfont.js | 71 + web/src/assets/svg/llm/ai302.svg | 1 - web/src/assets/svg/llm/anthropic.svg | 1 - web/src/assets/svg/llm/azure.svg | 1 - web/src/assets/svg/llm/baai.svg | 12 - web/src/assets/svg/llm/baichuan.svg | 28 - web/src/assets/svg/llm/bedrock.svg | 29 - web/src/assets/svg/llm/cohere.svg | 1 - web/src/assets/svg/llm/cometapi.svg | 6 - web/src/assets/svg/llm/deepinfra.svg | 1 - web/src/assets/svg/llm/deepseek.svg | 6 - web/src/assets/svg/llm/deerapi.svg | 5 - web/src/assets/svg/llm/fish-audio.svg | 1 - web/src/assets/svg/llm/gitee-ai.svg | 6 - web/src/assets/svg/llm/github.svg | 10 - web/src/assets/svg/llm/google-cloud.svg | 1 - web/src/assets/svg/llm/google.svg | 13 - web/src/assets/svg/llm/gpustack.svg | 14 - web/src/assets/svg/llm/grok.svg | 1 - web/src/assets/svg/llm/groq-next.svg | 1 - web/src/assets/svg/llm/huggingface.svg | 37 - web/src/assets/svg/llm/hunyuan.svg | 1 - web/src/assets/svg/llm/jina.svg | 12 - web/src/assets/svg/llm/lepton-ai.svg | 44 - web/src/assets/svg/llm/lm-studio.svg | 9704 ----------------- web/src/assets/svg/llm/longcat.svg | 7 - web/src/assets/svg/llm/mistral.svg | 24 - web/src/assets/svg/llm/modelscope.svg | 1 - web/src/assets/svg/llm/moonshot.svg | 6 - web/src/assets/svg/llm/nomic-ai.svg | 7 - web/src/assets/svg/llm/novita-ai.svg | 3 - web/src/assets/svg/llm/nvidia.svg | 1 - web/src/assets/svg/llm/ollama.svg | 9 - web/src/assets/svg/llm/open-router.svg | 17 - web/src/assets/svg/llm/openai-api.svg | 1 - web/src/assets/svg/llm/openai.svg | 6 - web/src/assets/svg/llm/perfx-cloud.svg | 10 - web/src/assets/svg/llm/ppio.svg | 3 - web/src/assets/svg/llm/replicate.svg | 1 - .../assets/svg/llm/sentence-transformers.svg | 29 - web/src/assets/svg/llm/siliconflow.svg | 13 - web/src/assets/svg/llm/spark.svg | 1 - web/src/assets/svg/llm/tencent-cloud.svg | 1 - web/src/assets/svg/llm/together-ai.svg | 36 - web/src/assets/svg/llm/token-pony.svg | 8 - web/src/assets/svg/llm/tongyi.svg | 7 - web/src/assets/svg/llm/upstage.svg | 255 - web/src/assets/svg/llm/vllm.svg | 59 - web/src/assets/svg/llm/volc_engine.svg | 14 - web/src/assets/svg/llm/voyage.svg | 32 - web/src/assets/svg/llm/xai.svg | 1 - web/src/assets/svg/llm/xinference.svg | 39 - web/src/assets/svg/llm/yi.svg | 7 - web/src/assets/svg/llm/yiyan.svg | 1 - web/src/assets/svg/llm/youdao.svg | 13 - web/src/assets/svg/llm/zhipu.svg | 12 - .../raptor-form-fields.tsx | 33 + web/src/components/svg-icon.tsx | 48 +- web/src/constants/llm.ts | 16 +- web/src/hooks/llm-hooks.tsx | 4 +- web/src/locales/en.ts | 13 +- web/src/locales/zh.ts | 13 +- .../pages/dataset/dataset-overview/hook.ts | 6 +- .../pages/dataset/dataset-overview/index.tsx | 4 + .../dataset/dataset-overview/interface.ts | 3 +- .../dataset/dataset-setting/form-schema.ts | 1 + .../pages/dataset/dataset-setting/index.tsx | 3 +- web/src/pages/login-next/index.tsx | 2 +- web/src/pages/login/index.less | 133 - web/src/pages/login/index.tsx | 206 - web/src/pages/login/right-panel.tsx | 47 - .../user-setting/data-source/contant.tsx | 7 +- .../setting-model/components/un-add-model.tsx | 5 +- web/src/pages/user-setting/sidebar/index.tsx | 9 +- 74 files changed, 203 insertions(+), 10981 deletions(-) delete mode 100644 web/src/assets/svg/llm/ai302.svg delete mode 100644 web/src/assets/svg/llm/anthropic.svg delete mode 100644 web/src/assets/svg/llm/azure.svg delete mode 100644 web/src/assets/svg/llm/baai.svg delete mode 100644 web/src/assets/svg/llm/baichuan.svg delete mode 100644 web/src/assets/svg/llm/bedrock.svg delete mode 100644 web/src/assets/svg/llm/cohere.svg delete mode 100644 web/src/assets/svg/llm/cometapi.svg delete mode 100644 web/src/assets/svg/llm/deepinfra.svg delete mode 100644 web/src/assets/svg/llm/deepseek.svg delete mode 100644 web/src/assets/svg/llm/deerapi.svg delete mode 100644 web/src/assets/svg/llm/fish-audio.svg delete mode 100644 web/src/assets/svg/llm/gitee-ai.svg delete mode 100644 web/src/assets/svg/llm/github.svg delete mode 100644 web/src/assets/svg/llm/google-cloud.svg delete mode 100644 web/src/assets/svg/llm/google.svg delete mode 100644 web/src/assets/svg/llm/gpustack.svg delete mode 100644 web/src/assets/svg/llm/grok.svg delete mode 100644 web/src/assets/svg/llm/groq-next.svg delete mode 100644 web/src/assets/svg/llm/huggingface.svg delete mode 100644 web/src/assets/svg/llm/hunyuan.svg delete mode 100644 web/src/assets/svg/llm/jina.svg delete mode 100644 web/src/assets/svg/llm/lepton-ai.svg delete mode 100644 web/src/assets/svg/llm/lm-studio.svg delete mode 100644 web/src/assets/svg/llm/longcat.svg delete mode 100644 web/src/assets/svg/llm/mistral.svg delete mode 100644 web/src/assets/svg/llm/modelscope.svg delete mode 100644 web/src/assets/svg/llm/moonshot.svg delete mode 100644 web/src/assets/svg/llm/nomic-ai.svg delete mode 100644 web/src/assets/svg/llm/novita-ai.svg delete mode 100644 web/src/assets/svg/llm/nvidia.svg delete mode 100644 web/src/assets/svg/llm/ollama.svg delete mode 100644 web/src/assets/svg/llm/open-router.svg delete mode 100644 web/src/assets/svg/llm/openai-api.svg delete mode 100644 web/src/assets/svg/llm/openai.svg delete mode 100644 web/src/assets/svg/llm/perfx-cloud.svg delete mode 100755 web/src/assets/svg/llm/ppio.svg delete mode 100644 web/src/assets/svg/llm/replicate.svg delete mode 100644 web/src/assets/svg/llm/sentence-transformers.svg delete mode 100644 web/src/assets/svg/llm/siliconflow.svg delete mode 100644 web/src/assets/svg/llm/spark.svg delete mode 100644 web/src/assets/svg/llm/tencent-cloud.svg delete mode 100644 web/src/assets/svg/llm/together-ai.svg delete mode 100644 web/src/assets/svg/llm/token-pony.svg delete mode 100644 web/src/assets/svg/llm/tongyi.svg delete mode 100644 web/src/assets/svg/llm/upstage.svg delete mode 100644 web/src/assets/svg/llm/vllm.svg delete mode 100644 web/src/assets/svg/llm/volc_engine.svg delete mode 100644 web/src/assets/svg/llm/voyage.svg delete mode 100644 web/src/assets/svg/llm/xai.svg delete mode 100644 web/src/assets/svg/llm/xinference.svg delete mode 100644 web/src/assets/svg/llm/yi.svg delete mode 100644 web/src/assets/svg/llm/yiyan.svg delete mode 100644 web/src/assets/svg/llm/youdao.svg delete mode 100644 web/src/assets/svg/llm/zhipu.svg delete mode 100644 web/src/pages/login/index.less delete mode 100644 web/src/pages/login/index.tsx delete mode 100644 web/src/pages/login/right-panel.tsx diff --git a/web/public/iconfont.js b/web/public/iconfont.js index 6b2c93e8f62..178288a11e7 100644 --- a/web/public/iconfont.js +++ b/web/public/iconfont.js @@ -1,5 +1,76 @@ (window._iconfont_svg_string_4909832 = '' + + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ` + '' + '' + '' + diff --git a/web/src/assets/svg/llm/ai302.svg b/web/src/assets/svg/llm/ai302.svg deleted file mode 100644 index 80a864ee942..00000000000 --- a/web/src/assets/svg/llm/ai302.svg +++ /dev/null @@ -1 +0,0 @@ -302.AI \ No newline at end of file diff --git a/web/src/assets/svg/llm/anthropic.svg b/web/src/assets/svg/llm/anthropic.svg deleted file mode 100644 index 249c9503cb8..00000000000 --- a/web/src/assets/svg/llm/anthropic.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/azure.svg b/web/src/assets/svg/llm/azure.svg deleted file mode 100644 index b3281a5a571..00000000000 --- a/web/src/assets/svg/llm/azure.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/baai.svg b/web/src/assets/svg/llm/baai.svg deleted file mode 100644 index 7e365e37707..00000000000 --- a/web/src/assets/svg/llm/baai.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/baichuan.svg b/web/src/assets/svg/llm/baichuan.svg deleted file mode 100644 index 6ea61b5b815..00000000000 --- a/web/src/assets/svg/llm/baichuan.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - diff --git a/web/src/assets/svg/llm/bedrock.svg b/web/src/assets/svg/llm/bedrock.svg deleted file mode 100644 index 3b01a13a483..00000000000 --- a/web/src/assets/svg/llm/bedrock.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - diff --git a/web/src/assets/svg/llm/cohere.svg b/web/src/assets/svg/llm/cohere.svg deleted file mode 100644 index cb1b2a5919e..00000000000 --- a/web/src/assets/svg/llm/cohere.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/cometapi.svg b/web/src/assets/svg/llm/cometapi.svg deleted file mode 100644 index 8d981186468..00000000000 --- a/web/src/assets/svg/llm/cometapi.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/web/src/assets/svg/llm/deepinfra.svg b/web/src/assets/svg/llm/deepinfra.svg deleted file mode 100644 index 565c8095b58..00000000000 --- a/web/src/assets/svg/llm/deepinfra.svg +++ /dev/null @@ -1 +0,0 @@ -DeepInfra \ No newline at end of file diff --git a/web/src/assets/svg/llm/deepseek.svg b/web/src/assets/svg/llm/deepseek.svg deleted file mode 100644 index 50a8eb318b5..00000000000 --- a/web/src/assets/svg/llm/deepseek.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/deerapi.svg b/web/src/assets/svg/llm/deerapi.svg deleted file mode 100644 index 0655cd5ed3b..00000000000 --- a/web/src/assets/svg/llm/deerapi.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/web/src/assets/svg/llm/fish-audio.svg b/web/src/assets/svg/llm/fish-audio.svg deleted file mode 100644 index ec44029a902..00000000000 --- a/web/src/assets/svg/llm/fish-audio.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/gitee-ai.svg b/web/src/assets/svg/llm/gitee-ai.svg deleted file mode 100644 index 93a3cea676c..00000000000 --- a/web/src/assets/svg/llm/gitee-ai.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/github.svg b/web/src/assets/svg/llm/github.svg deleted file mode 100644 index 6f80a87ed11..00000000000 --- a/web/src/assets/svg/llm/github.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/web/src/assets/svg/llm/google-cloud.svg b/web/src/assets/svg/llm/google-cloud.svg deleted file mode 100644 index 2f7870552c5..00000000000 --- a/web/src/assets/svg/llm/google-cloud.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/google.svg b/web/src/assets/svg/llm/google.svg deleted file mode 100644 index f0d10ecfd99..00000000000 --- a/web/src/assets/svg/llm/google.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/web/src/assets/svg/llm/gpustack.svg b/web/src/assets/svg/llm/gpustack.svg deleted file mode 100644 index 95a07f912bc..00000000000 --- a/web/src/assets/svg/llm/gpustack.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - Combined Shape - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/grok.svg b/web/src/assets/svg/llm/grok.svg deleted file mode 100644 index 9201bbc9ff9..00000000000 --- a/web/src/assets/svg/llm/grok.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/groq-next.svg b/web/src/assets/svg/llm/groq-next.svg deleted file mode 100644 index 5608a42e4fc..00000000000 --- a/web/src/assets/svg/llm/groq-next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/huggingface.svg b/web/src/assets/svg/llm/huggingface.svg deleted file mode 100644 index 43c5d3c0c97..00000000000 --- a/web/src/assets/svg/llm/huggingface.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - diff --git a/web/src/assets/svg/llm/hunyuan.svg b/web/src/assets/svg/llm/hunyuan.svg deleted file mode 100644 index 43a78d0077a..00000000000 --- a/web/src/assets/svg/llm/hunyuan.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/jina.svg b/web/src/assets/svg/llm/jina.svg deleted file mode 100644 index 6a241fc9ae3..00000000000 --- a/web/src/assets/svg/llm/jina.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/web/src/assets/svg/llm/lepton-ai.svg b/web/src/assets/svg/llm/lepton-ai.svg deleted file mode 100644 index b7ccd3d26e2..00000000000 --- a/web/src/assets/svg/llm/lepton-ai.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - diff --git a/web/src/assets/svg/llm/lm-studio.svg b/web/src/assets/svg/llm/lm-studio.svg deleted file mode 100644 index 98d4c1d990c..00000000000 --- a/web/src/assets/svg/llm/lm-studio.svg +++ /dev/null @@ -1,9704 +0,0 @@ - - - - diff --git a/web/src/assets/svg/llm/longcat.svg b/web/src/assets/svg/llm/longcat.svg deleted file mode 100644 index f123daf3a38..00000000000 --- a/web/src/assets/svg/llm/longcat.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/web/src/assets/svg/llm/mistral.svg b/web/src/assets/svg/llm/mistral.svg deleted file mode 100644 index b4a57ef79fa..00000000000 --- a/web/src/assets/svg/llm/mistral.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/modelscope.svg b/web/src/assets/svg/llm/modelscope.svg deleted file mode 100644 index 8b3778fc456..00000000000 --- a/web/src/assets/svg/llm/modelscope.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/src/assets/svg/llm/moonshot.svg b/web/src/assets/svg/llm/moonshot.svg deleted file mode 100644 index dbaf1f64734..00000000000 --- a/web/src/assets/svg/llm/moonshot.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/nomic-ai.svg b/web/src/assets/svg/llm/nomic-ai.svg deleted file mode 100644 index 26e624a88b8..00000000000 --- a/web/src/assets/svg/llm/nomic-ai.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/web/src/assets/svg/llm/novita-ai.svg b/web/src/assets/svg/llm/novita-ai.svg deleted file mode 100644 index c44bd707b7c..00000000000 --- a/web/src/assets/svg/llm/novita-ai.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/src/assets/svg/llm/nvidia.svg b/web/src/assets/svg/llm/nvidia.svg deleted file mode 100644 index 217afaac9ca..00000000000 --- a/web/src/assets/svg/llm/nvidia.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/ollama.svg b/web/src/assets/svg/llm/ollama.svg deleted file mode 100644 index 6e9fb283c01..00000000000 --- a/web/src/assets/svg/llm/ollama.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/web/src/assets/svg/llm/open-router.svg b/web/src/assets/svg/llm/open-router.svg deleted file mode 100644 index e6130e73d41..00000000000 --- a/web/src/assets/svg/llm/open-router.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/openai-api.svg b/web/src/assets/svg/llm/openai-api.svg deleted file mode 100644 index a0ecf992f46..00000000000 --- a/web/src/assets/svg/llm/openai-api.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/openai.svg b/web/src/assets/svg/llm/openai.svg deleted file mode 100644 index 6114c7c7ed6..00000000000 --- a/web/src/assets/svg/llm/openai.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/perfx-cloud.svg b/web/src/assets/svg/llm/perfx-cloud.svg deleted file mode 100644 index 3767a1e8664..00000000000 --- a/web/src/assets/svg/llm/perfx-cloud.svg +++ /dev/null @@ -1,10 +0,0 @@ - - logo - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/ppio.svg b/web/src/assets/svg/llm/ppio.svg deleted file mode 100755 index 49ab9a1f6c8..00000000000 --- a/web/src/assets/svg/llm/ppio.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/src/assets/svg/llm/replicate.svg b/web/src/assets/svg/llm/replicate.svg deleted file mode 100644 index 31241923ed3..00000000000 --- a/web/src/assets/svg/llm/replicate.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/sentence-transformers.svg b/web/src/assets/svg/llm/sentence-transformers.svg deleted file mode 100644 index f777b3d26cc..00000000000 --- a/web/src/assets/svg/llm/sentence-transformers.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/siliconflow.svg b/web/src/assets/svg/llm/siliconflow.svg deleted file mode 100644 index c6785062867..00000000000 --- a/web/src/assets/svg/llm/siliconflow.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/spark.svg b/web/src/assets/svg/llm/spark.svg deleted file mode 100644 index 30f6040f24f..00000000000 --- a/web/src/assets/svg/llm/spark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/tencent-cloud.svg b/web/src/assets/svg/llm/tencent-cloud.svg deleted file mode 100644 index b33a9701a1f..00000000000 --- a/web/src/assets/svg/llm/tencent-cloud.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/together-ai.svg b/web/src/assets/svg/llm/together-ai.svg deleted file mode 100644 index 93e744c3df2..00000000000 --- a/web/src/assets/svg/llm/together-ai.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/token-pony.svg b/web/src/assets/svg/llm/token-pony.svg deleted file mode 100644 index a504e222408..00000000000 --- a/web/src/assets/svg/llm/token-pony.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - logo2 - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/tongyi.svg b/web/src/assets/svg/llm/tongyi.svg deleted file mode 100644 index d7104d6d370..00000000000 --- a/web/src/assets/svg/llm/tongyi.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/upstage.svg b/web/src/assets/svg/llm/upstage.svg deleted file mode 100644 index 09a7512ca94..00000000000 --- a/web/src/assets/svg/llm/upstage.svg +++ /dev/null @@ -1,255 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/vllm.svg b/web/src/assets/svg/llm/vllm.svg deleted file mode 100644 index 6aca3848649..00000000000 --- a/web/src/assets/svg/llm/vllm.svg +++ /dev/null @@ -1,59 +0,0 @@ - - vllm - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/volc_engine.svg b/web/src/assets/svg/llm/volc_engine.svg deleted file mode 100644 index 2c56cb00bdd..00000000000 --- a/web/src/assets/svg/llm/volc_engine.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/voyage.svg b/web/src/assets/svg/llm/voyage.svg deleted file mode 100644 index 88ffbdff91c..00000000000 --- a/web/src/assets/svg/llm/voyage.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/xai.svg b/web/src/assets/svg/llm/xai.svg deleted file mode 100644 index a6808fb67b7..00000000000 --- a/web/src/assets/svg/llm/xai.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/xinference.svg b/web/src/assets/svg/llm/xinference.svg deleted file mode 100644 index 8d2ab4f3e4d..00000000000 --- a/web/src/assets/svg/llm/xinference.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/yi.svg b/web/src/assets/svg/llm/yi.svg deleted file mode 100644 index 83ebd22d9f1..00000000000 --- a/web/src/assets/svg/llm/yi.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/web/src/assets/svg/llm/yiyan.svg b/web/src/assets/svg/llm/yiyan.svg deleted file mode 100644 index 4c571c34a07..00000000000 --- a/web/src/assets/svg/llm/yiyan.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/web/src/assets/svg/llm/youdao.svg b/web/src/assets/svg/llm/youdao.svg deleted file mode 100644 index 5af58851fd3..00000000000 --- a/web/src/assets/svg/llm/youdao.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/web/src/assets/svg/llm/zhipu.svg b/web/src/assets/svg/llm/zhipu.svg deleted file mode 100644 index 5561830e619..00000000000 --- a/web/src/assets/svg/llm/zhipu.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/src/components/parse-configuration/raptor-form-fields.tsx b/web/src/components/parse-configuration/raptor-form-fields.tsx index 2e03526c5d8..4f99ecadcb2 100644 --- a/web/src/components/parse-configuration/raptor-form-fields.tsx +++ b/web/src/components/parse-configuration/raptor-form-fields.tsx @@ -19,6 +19,7 @@ import { FormMessage, } from '../ui/form'; import { ExpandedInput } from '../ui/input'; +import { Radio } from '../ui/radio'; import { Textarea } from '../ui/textarea'; export const excludedParseMethods = [ @@ -111,6 +112,38 @@ const RaptorFormFields = ({ ); }} /> + { + return ( + +
+ + {t('generationScope')} + +
+ + +
+ {t('scopeDataset')} + {t('scopeSingleFile')} +
+
+
+
+
+
+
+ +
+ + ); + }} + /> {useRaptor && (
{ @@ -61,15 +63,45 @@ export const LlmIcon = ({ size?: AvatarSize; imgClass?: string; }) => { - const icon = IconMap[name as keyof typeof IconMap]; + const isDark = useIsDarkTheme(); + const themeIcons = [ + LLMFactory.FishAudio, + LLMFactory.TogetherAI, + LLMFactory.Meituan, + ]; + let icon = useMemo(() => { + const icontemp = IconMap[name as keyof typeof IconMap]; + if (themeIcons.includes(name as LLMFactory)) { + if (isDark) { + return icontemp + '-dark'; + } else { + return icontemp + '-bright'; + } + } + return icontemp; + }, [name, isDark]); + + const svgIcons = [ + LLMFactory.LocalAI, + // LLMFactory.VolcEngine, + LLMFactory.MiniMax, + LLMFactory.Gemini, + LLMFactory.StepFun, + // LLMFactory.DeerAPI, + ]; + if (svgIcons.includes(name as LLMFactory)) { + return ( + + ); + } return icon ? ( - + ) : ( } /> ); diff --git a/web/src/constants/llm.ts b/web/src/constants/llm.ts index c5333fd3e29..6282dd1ef39 100644 --- a/web/src/constants/llm.ts +++ b/web/src/constants/llm.ts @@ -31,7 +31,6 @@ export enum LLMFactory { NovitaAI = 'NovitaAI', SILICONFLOW = 'SILICONFLOW', PPIO = 'PPIO', - ZeroOneAI = '01.AI', Replicate = 'Replicate', TencentHunYuan = 'Tencent Hunyuan', XunFeiSpark = 'XunFei Spark', @@ -58,11 +57,12 @@ export enum LLMFactory { Meituan = 'Meituan', CometAPI = 'CometAPI', DeerAPI = 'DeerAPI', + Builtin = 'Builtin', } // Please lowercase the file name export const IconMap = { - [LLMFactory.TongYiQianWen]: 'tongyi', + [LLMFactory.TongYiQianWen]: 'tongyi-qianwen', [LLMFactory.Moonshot]: 'moonshot', [LLMFactory.OpenAI]: 'openai', [LLMFactory.ZhipuAI]: 'zhipu', @@ -71,7 +71,7 @@ export const IconMap = { [LLMFactory.Xinference]: 'xinference', [LLMFactory.ModelScope]: 'modelscope', [LLMFactory.DeepSeek]: 'deepseek', - [LLMFactory.VolcEngine]: 'volc_engine', + [LLMFactory.VolcEngine]: 'volcengine', [LLMFactory.BaiChuan]: 'baichuan', [LLMFactory.Jina]: 'jina', [LLMFactory.MiniMax]: 'chat-minimax', @@ -87,18 +87,17 @@ export const IconMap = { [LLMFactory.LMStudio]: 'lm-studio', [LLMFactory.OpenAiAPICompatible]: 'openai-api', [LLMFactory.Cohere]: 'cohere', - [LLMFactory.LeptonAI]: 'lepton-ai', - [LLMFactory.TogetherAI]: 'together-ai', + [LLMFactory.LeptonAI]: 'lepton', + [LLMFactory.TogetherAI]: 'together', [LLMFactory.PerfXCloud]: 'perfx-cloud', [LLMFactory.Upstage]: 'upstage', [LLMFactory.NovitaAI]: 'novita-ai', [LLMFactory.SILICONFLOW]: 'siliconflow', [LLMFactory.PPIO]: 'ppio', - [LLMFactory.ZeroOneAI]: 'yi', [LLMFactory.Replicate]: 'replicate', [LLMFactory.TencentHunYuan]: 'hunyuan', [LLMFactory.XunFeiSpark]: 'spark', - [LLMFactory.BaiduYiYan]: 'yiyan', + [LLMFactory.BaiduYiYan]: 'wenxinyiyan', [LLMFactory.FishAudio]: 'fish-audio', [LLMFactory.TencentCloud]: 'tencent-cloud', [LLMFactory.Anthropic]: 'anthropic', @@ -117,8 +116,9 @@ export const IconMap = { [LLMFactory.DeepInfra]: 'deepinfra', [LLMFactory.Grok]: 'grok', [LLMFactory.XAI]: 'xai', - [LLMFactory.TokenPony]: 'token-pony', + [LLMFactory.TokenPony]: 'tokenpony', [LLMFactory.Meituan]: 'longcat', [LLMFactory.CometAPI]: 'cometapi', [LLMFactory.DeerAPI]: 'deerapi', + [LLMFactory.Builtin]: 'builtin', }; diff --git a/web/src/hooks/llm-hooks.tsx b/web/src/hooks/llm-hooks.tsx index 7ea9228c9d6..0da63f7b56f 100644 --- a/web/src/hooks/llm-hooks.tsx +++ b/web/src/hooks/llm-hooks.tsx @@ -14,7 +14,6 @@ import { IDeleteLlmRequestBody, } from '@/interfaces/request/llm'; import userService from '@/services/user-service'; -import { sortLLmFactoryListBySpecifiedOrder } from '@/utils/common-util'; import { getLLMIconName, getRealModelName } from '@/utils/llm-util'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { DefaultOptionType } from 'antd/es/select'; @@ -239,7 +238,8 @@ export const useSelectLlmList = () => { const currentList = factoryList.filter((x) => Object.keys(myLlmList).every((y) => y !== x.name), ); - return sortLLmFactoryListBySpecifiedOrder(currentList); + return currentList; + // return sortLLmFactoryListBySpecifiedOrder(currentList); }, [factoryList, myLlmList]); return { diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index e89e6823d17..7b0909d41e9 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -274,11 +274,16 @@ export default { reRankModelWaring: 'Re-rank model is very time consuming.', }, knowledgeConfiguration: { + generationScopeTip: + 'Determines whether RAPTOR is generated for the entire dataset or for a single file.', + scopeDataset: 'Dataset', + generationScope: 'Generation Scope', + scopeSingleFile: 'Single File', autoParse: 'Auto Parse', rebuildTip: 'Re-downloads files from the linked data source and parses them again.', baseInfo: 'Basic Info', - gobalIndex: 'Global Index', + globalIndex: 'Global Index', dataSource: 'Data Source', linkSourceSetTip: 'Manage data source linkage with this dataset', linkDataSource: 'Link Data Source', @@ -688,6 +693,12 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s tocEnhanceTip: ` During the parsing of the document, table of contents information was generated (see the 'Enable Table of Contents Extraction' option in the General method). This allows the large model to return table of contents items relevant to the user's query, thereby using these items to retrieve related chunks and apply weighting to these chunks during the sorting process. This approach is derived from mimicking the behavioral logic of how humans search for knowledge in books.`, }, setting: { + confluenceIsCloudTip: + 'Check if this is a Confluence Cloud instance, uncheck for Confluence Server/Data Center', + confluenceWikiBaseUrlTip: + 'The base URL of your Confluence instance (e.g., https://your-domain.atlassian.net/wiki)', + s3PrefixTip: `Specify the folder path within your S3 bucket to fetch files from. +Example: general/v2/`, addDataSourceModalTital: 'Create your {{name}} connector', deleteSourceModalTitle: 'Delete data source', deleteSourceModalContent: ` diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index c7d21477d49..13b4bb0d98e 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -260,10 +260,15 @@ export default { theDocumentBeingParsedCannotBeDeleted: '正在解析的文档不能被删除', }, knowledgeConfiguration: { + generationScopeTip: '选择 RAPTOR 的生成范围:整个知识库或单个文件。', + generationScope: '生成范围', + scopeSingleFile: '单文件', + scopeDataset: '整库', + autoParse: '自动解析', rebuildTip: '从所有已关联的数据源重新下载文件并再次解析。', baseInfo: '基础信息', - gobalIndex: '全局索引', + globalIndex: '全局索引', dataSource: '数据源', linkSourceSetTip: '管理与此数据集的数据源链接', linkDataSource: '链接数据源', @@ -678,6 +683,12 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`, }, setting: { + confluenceIsCloudTip: + '检查这是否是 Confluence Cloud 实例,如果是 Confluence 服务/数据中心,则取消选中。', + confluenceWikiBaseUrlTip: + 'Confluence Wiki 的基础 URL(例如 https://your-domain.atlassian.net/wiki)', + s3PrefixTip: `指定 S3 存储桶内的文件夹路径,用于读取文件。 +示例:general/v2/`, addDataSourceModalTital: '创建你的 {{name}} 链接', deleteSourceModalTitle: '删除数据源链接', deleteSourceModalContent: ` diff --git a/web/src/pages/dataset/dataset-overview/hook.ts b/web/src/pages/dataset/dataset-overview/hook.ts index 62453a31e22..a74dd947ce1 100644 --- a/web/src/pages/dataset/dataset-overview/hook.ts +++ b/web/src/pages/dataset/dataset-overview/hook.ts @@ -11,14 +11,14 @@ import { useQuery } from '@tanstack/react-query'; import { useCallback, useState } from 'react'; import { useParams, useSearchParams } from 'umi'; import { LogTabs } from './dataset-common'; -import { IFileLogList, IOverviewTital } from './interface'; +import { IFileLogList, IOverviewTotal } from './interface'; const useFetchOverviewTital = () => { const [searchParams] = useSearchParams(); const { id } = useParams(); const knowledgeBaseId = searchParams.get('id') || id; - const { data } = useQuery({ - queryKey: ['overviewTital'], + const { data } = useQuery({ + queryKey: ['overviewTotal'], queryFn: async () => { const { data: res = {} } = await kbService.getKnowledgeBasicInfo({ kb_id: knowledgeBaseId, diff --git a/web/src/pages/dataset/dataset-overview/index.tsx b/web/src/pages/dataset/dataset-overview/index.tsx index babc3b7d29a..7da96a576ee 100644 --- a/web/src/pages/dataset/dataset-overview/index.tsx +++ b/web/src/pages/dataset/dataset-overview/index.tsx @@ -128,6 +128,10 @@ const FileLogsPage: FC = () => { setTopAllData((prev) => { return { ...prev, + downloads: { + ...prev.downloads, + success: topData?.downloaded || 0, + }, processing: { value: topData?.processing || 0, success: topData?.finished || 0, diff --git a/web/src/pages/dataset/dataset-overview/interface.ts b/web/src/pages/dataset/dataset-overview/interface.ts index 72991e4acc0..795b50bbcd1 100644 --- a/web/src/pages/dataset/dataset-overview/interface.ts +++ b/web/src/pages/dataset/dataset-overview/interface.ts @@ -20,11 +20,12 @@ export interface FileLogsTableProps { active: (typeof LogTabs)[keyof typeof LogTabs]; } -export interface IOverviewTital { +export interface IOverviewTotal { cancelled: number; failed: number; finished: number; processing: number; + downloaded: number; } export interface IFileLogItem { diff --git a/web/src/pages/dataset/dataset-setting/form-schema.ts b/web/src/pages/dataset/dataset-setting/form-schema.ts index a306e859455..51d4afc3da9 100644 --- a/web/src/pages/dataset/dataset-setting/form-schema.ts +++ b/web/src/pages/dataset/dataset-setting/form-schema.ts @@ -37,6 +37,7 @@ export const formSchema = z threshold: z.number().optional(), max_cluster: z.number().optional(), random_seed: z.number().optional(), + scope: z.string().optional(), }) .refine( (data) => { diff --git a/web/src/pages/dataset/dataset-setting/index.tsx b/web/src/pages/dataset/dataset-setting/index.tsx index 443cefaf183..5a9b5c4bc1c 100644 --- a/web/src/pages/dataset/dataset-setting/index.tsx +++ b/web/src/pages/dataset/dataset-setting/index.tsx @@ -73,6 +73,7 @@ export default function DatasetSettings() { threshold: 0.1, max_cluster: 64, random_seed: 0, + scope: 'file', prompt: t('knowledgeConfiguration.promptText'), }, graphrag: { @@ -252,7 +253,7 @@ export default function DatasetSettings() {
- {t('knowledgeConfiguration.gobalIndex')} + {t('knowledgeConfiguration.globalIndex')}
{ {/* */}
-
+
logo { - const [title, setTitle] = useState('login'); - const navigate = useNavigate(); - const { login, loading: signLoading } = useLogin(); - const { register, loading: registerLoading } = useRegister(); - const { channels, loading: channelsLoading } = useLoginChannels(); - const { login: loginWithChannel, loading: loginWithChannelLoading } = - useLoginWithChannel(); - const { t } = useTranslation('translation', { keyPrefix: 'login' }); - const loading = - signLoading || - registerLoading || - channelsLoading || - loginWithChannelLoading; - const { config } = useSystemConfig(); - const registerEnabled = config?.registerEnabled !== 0; - - const { isLogin } = useAuth(); - useEffect(() => { - if (isLogin) { - navigate('/'); - } - }, [isLogin, navigate]); - - const handleLoginWithChannel = async (channel: string) => { - await loginWithChannel(channel); - }; - - const changeTitle = () => { - if (title === 'login' && !registerEnabled) { - return; - } - setTitle((title) => (title === 'login' ? 'register' : 'login')); - }; - const [form] = Form.useForm(); - - useEffect(() => { - form.validateFields(['nickname']); - }, [form]); - - const onCheck = async () => { - try { - const params = await form.validateFields(); - - const rsaPassWord = rsaPsw(params.password) as string; - - if (title === 'login') { - const code = await login({ - email: `${params.email}`.trim(), - password: rsaPassWord, - }); - if (code === 0) { - navigate('/'); - } - } else { - const code = await register({ - nickname: params.nickname, - email: params.email, - password: rsaPassWord, - }); - if (code === 0) { - setTitle('login'); - } - } - } catch (errorInfo) { - console.log('Failed:', errorInfo); - } - }; - const formItemLayout = { - labelCol: { span: 6 }, - // wrapperCol: { span: 8 }, - }; - - return ( -
-
-
-
-
{title === 'login' ? t('login') : t('register')}
- - {title === 'login' - ? t('loginDescription') - : t('registerDescription')} - -
- -
- - - - {title === 'register' && ( - - - - )} - - - - {title === 'login' && ( - - {t('rememberMe')} - - )} -
- {title === 'login' && registerEnabled && ( -
- {t('signInTip')} - -
- )} - {title === 'register' && ( -
- {t('signUpTip')} - -
- )} -
- - {title === 'login' && channels && channels.length > 0 && ( -
- {channels.map((item) => ( - - ))} -
- )} -
-
-
-
- -
-
- ); -}; - -export default Login; diff --git a/web/src/pages/login/right-panel.tsx b/web/src/pages/login/right-panel.tsx deleted file mode 100644 index 820dd9b35f8..00000000000 --- a/web/src/pages/login/right-panel.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { ReactComponent as Avatars } from '@/assets/svg/login-avatars.svg'; -import SvgIcon from '@/components/svg-icon'; -import { Flex, Rate, Space, Typography } from 'antd'; -import classNames from 'classnames'; - -import { useTranslate } from '@/hooks/common-hooks'; -import styles from './index.less'; - -const { Title, Text } = Typography; - -const LoginRightPanel = () => { - const { t } = useTranslate('login'); - return ( -
- - - - {t('title')} - - - {t('description')} - - - - - - - - 5.0 - - - - {t('review')} - - - - -
- ); -}; - -export default LoginRightPanel; diff --git a/web/src/pages/user-setting/data-source/contant.tsx b/web/src/pages/user-setting/data-source/contant.tsx index c631f40eec6..ebb92619c84 100644 --- a/web/src/pages/user-setting/data-source/contant.tsx +++ b/web/src/pages/user-setting/data-source/contant.tsx @@ -108,6 +108,7 @@ export const DataSourceFormFields = { name: 'config.prefix', type: FormFieldType.Text, required: false, + tooltip: t('setting.s3PrefixTip'), }, ], [DataSourceKey.NOTION]: [ @@ -164,16 +165,14 @@ export const DataSourceFormFields = { name: 'config.wiki_base', type: FormFieldType.Text, required: false, - tooltip: - 'The base URL of your Confluence instance (e.g., https://your-domain.atlassian.net/wiki)', + tooltip: t('setting.confluenceWikiBaseUrlTip'), }, { label: 'Is Cloud', name: 'config.is_cloud', type: FormFieldType.Checkbox, required: false, - tooltip: - 'Check if this is a Confluence Cloud instance, uncheck for Confluence Server/Data Center', + tooltip: t('setting.confluenceIsCloudTip'), }, ], [DataSourceKey.GOOGLE_DRIVE]: [ diff --git a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx index a7a4425a38b..5d5c99d8c68 100644 --- a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx +++ b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx @@ -45,7 +45,7 @@ export const AvailableModels: FC<{ const [selectedTag, setSelectedTag] = useState(null); const filteredModels = useMemo(() => { - return factoryList.filter((model) => { + const models = factoryList.filter((model) => { const matchesSearch = model.name .toLowerCase() .includes(searchTerm.toLowerCase()); @@ -54,6 +54,7 @@ export const AvailableModels: FC<{ model.tags.split(',').some((tag) => tag.trim() === selectedTag); return matchesSearch && matchesTag; }); + return models; }, [factoryList, searchTerm, selectedTag]); const allTags = useMemo(() => { @@ -124,7 +125,7 @@ export const AvailableModels: FC<{ className=" border border-border-default rounded-lg p-3 hover:bg-bg-input transition-colors group" >
- +

{model.name}

diff --git a/web/src/pages/user-setting/sidebar/index.tsx b/web/src/pages/user-setting/sidebar/index.tsx index c1c1c1da1af..20f20fdde42 100644 --- a/web/src/pages/user-setting/sidebar/index.tsx +++ b/web/src/pages/user-setting/sidebar/index.tsx @@ -77,11 +77,11 @@ export function SideBar() { )} {item.label} - {item.key === Routes.System && ( + {/* {item.key === Routes.System && (
{version}
- )} + )} */} {/* {active && (
)} */} @@ -93,7 +93,10 @@ export function SideBar() {
-
+
+
+ {version} +
); }; diff --git a/web/src/components/file-upload-dialog/index.tsx b/web/src/components/file-upload-dialog/index.tsx index aea32b472c0..5b3c5146386 100644 --- a/web/src/components/file-upload-dialog/index.tsx +++ b/web/src/components/file-upload-dialog/index.tsx @@ -6,7 +6,6 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { IModalProps } from '@/interfaces/common'; import { zodResolver } from '@hookform/resolvers/zod'; import { TFunction } from 'i18next'; @@ -102,7 +101,7 @@ export function FileUploadDialog({ {t('fileManager.uploadFile')} - + {/* {t('fileManager.local')} {t('fileManager.s3')} @@ -114,7 +113,11 @@ export function FileUploadDialog({ > {t('common.comingSoon')} - + */} + {t('common.save')} diff --git a/web/src/components/svg-icon.tsx b/web/src/components/svg-icon.tsx index 7aa79aa04c8..d21e55acebb 100644 --- a/web/src/components/svg-icon.tsx +++ b/web/src/components/svg-icon.tsx @@ -68,6 +68,7 @@ export const LlmIcon = ({ LLMFactory.FishAudio, LLMFactory.TogetherAI, LLMFactory.Meituan, + LLMFactory.Longcat, ]; let icon = useMemo(() => { const icontemp = IconMap[name as keyof typeof IconMap]; @@ -84,7 +85,7 @@ export const LlmIcon = ({ const svgIcons = [ LLMFactory.LocalAI, // LLMFactory.VolcEngine, - LLMFactory.MiniMax, + // LLMFactory.MiniMax, LLMFactory.Gemini, LLMFactory.StepFun, // LLMFactory.DeerAPI, @@ -101,9 +102,16 @@ export const LlmIcon = ({ } return icon ? ( - + ) : ( - } /> + + // } /> ); }; diff --git a/web/src/components/ui/command.tsx b/web/src/components/ui/command.tsx index 698260b412f..10caef77d43 100644 --- a/web/src/components/ui/command.tsx +++ b/web/src/components/ui/command.tsx @@ -15,7 +15,7 @@ const Command = React.forwardRef< handleCancel()} - className="px-2 py-1 border border-input rounded-md hover:bg-muted" + className="px-2 py-1 border border-border-button rounded-md hover:bg-bg-card hover:text-text-primary " > {cancelText ?? t('modal.cancelText')} @@ -132,7 +132,7 @@ const Modal: ModalType = ({ return (
diff --git a/web/src/constants/llm.ts b/web/src/constants/llm.ts index 6282dd1ef39..0f85140d5b3 100644 --- a/web/src/constants/llm.ts +++ b/web/src/constants/llm.ts @@ -55,6 +55,7 @@ export enum LLMFactory { XAI = 'xAI', TokenPony = 'TokenPony', Meituan = 'Meituan', + Longcat = 'LongCat', CometAPI = 'CometAPI', DeerAPI = 'DeerAPI', Builtin = 'Builtin', @@ -74,7 +75,7 @@ export const IconMap = { [LLMFactory.VolcEngine]: 'volcengine', [LLMFactory.BaiChuan]: 'baichuan', [LLMFactory.Jina]: 'jina', - [LLMFactory.MiniMax]: 'chat-minimax', + [LLMFactory.MiniMax]: 'MiniMax', [LLMFactory.Mistral]: 'mistral', [LLMFactory.AzureOpenAI]: 'azure', [LLMFactory.Bedrock]: 'bedrock', @@ -118,6 +119,7 @@ export const IconMap = { [LLMFactory.XAI]: 'xai', [LLMFactory.TokenPony]: 'tokenpony', [LLMFactory.Meituan]: 'longcat', + [LLMFactory.Longcat]: 'longcat', [LLMFactory.CometAPI]: 'cometapi', [LLMFactory.DeerAPI]: 'deerapi', [LLMFactory.Builtin]: 'builtin', diff --git a/web/src/hooks/llm-hooks.tsx b/web/src/hooks/llm-hooks.tsx index 0da63f7b56f..274f31ae069 100644 --- a/web/src/hooks/llm-hooks.tsx +++ b/web/src/hooks/llm-hooks.tsx @@ -402,6 +402,7 @@ export const useDeleteFactory = () => { queryClient.invalidateQueries({ queryKey: ['myLlmList'] }); queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] }); queryClient.invalidateQueries({ queryKey: ['factoryList'] }); + queryClient.invalidateQueries({ queryKey: ['llmList'] }); message.success(t('message.deleted')); } return data.code; diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 7b0909d41e9..92a9d53b5b5 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1,6 +1,7 @@ export default { translation: { common: { + back: 'Back', noResults: 'No results.', selectPlaceholder: 'select value', selectAll: 'Select all', @@ -693,6 +694,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s tocEnhanceTip: ` During the parsing of the document, table of contents information was generated (see the 'Enable Table of Contents Extraction' option in the General method). This allows the large model to return table of contents items relevant to the user's query, thereby using these items to retrieve related chunks and apply weighting to these chunks during the sorting process. This approach is derived from mimicking the behavioral logic of how humans search for knowledge in books.`, }, setting: { + configureModelTitle: 'Configure model', confluenceIsCloudTip: 'Check if this is a Confluence Cloud instance, uncheck for Confluence Server/Data Center', confluenceWikiBaseUrlTip: diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 13b4bb0d98e..9c90d734bdf 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1,6 +1,7 @@ export default { translation: { common: { + back: '返回', noResults: '无结果。', selectPlaceholder: '请选择', selectAll: '全选', @@ -683,6 +684,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`, }, setting: { + configureModelTitle: '配置模型', confluenceIsCloudTip: '检查这是否是 Confluence Cloud 实例,如果是 Confluence 服务/数据中心,则取消选中。', confluenceWikiBaseUrlTip: diff --git a/web/src/pages/login-next/index.tsx b/web/src/pages/login-next/index.tsx index 1aa9b2aa529..c9354225f80 100644 --- a/web/src/pages/login-next/index.tsx +++ b/web/src/pages/login-next/index.tsx @@ -157,7 +157,7 @@ const Login = () => { {/* */}
-
+
logo -
+
{ hideModal?.(); diff --git a/web/src/pages/user-setting/setting-model/components/modal-card.tsx b/web/src/pages/user-setting/setting-model/components/modal-card.tsx index 270f9b4b544..9bf2875f5c0 100644 --- a/web/src/pages/user-setting/setting-model/components/modal-card.tsx +++ b/web/src/pages/user-setting/setting-model/components/modal-card.tsx @@ -65,7 +65,7 @@ export const ModelProviderCard: FC = ({ }; return ( -
+
{/* Header */}
@@ -131,7 +131,7 @@ export const ModelProviderCard: FC = ({ {item.llm.map((model) => (
diff --git a/web/src/pages/user-setting/setting-model/components/system-setting.tsx b/web/src/pages/user-setting/setting-model/components/system-setting.tsx index f668132812c..2c87ab3b45f 100644 --- a/web/src/pages/user-setting/setting-model/components/system-setting.tsx +++ b/web/src/pages/user-setting/setting-model/components/system-setting.tsx @@ -156,7 +156,7 @@ const SystemSetting = ({ onOk, loading }: IProps) => { )} { {t('systemModelDescription')}
-
+
{llmList.map((item) => ( ))} diff --git a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx index 5d5c99d8c68..3d8b1d5e274 100644 --- a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx +++ b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx @@ -122,7 +122,7 @@ export const AvailableModels: FC<{ {filteredModels.map((model) => (
diff --git a/web/src/pages/user-setting/setting-model/components/used-model.tsx b/web/src/pages/user-setting/setting-model/components/used-model.tsx index dae26757913..6555caafc2e 100644 --- a/web/src/pages/user-setting/setting-model/components/used-model.tsx +++ b/web/src/pages/user-setting/setting-model/components/used-model.tsx @@ -11,7 +11,7 @@ export const UsedModel = ({ }) => { const { factoryList, myLlmList: llmList, loading } = useSelectLlmList(); return ( -
+
{t('setting.addedModels')}
diff --git a/web/src/pages/user-setting/setting-model/hooks.ts b/web/src/pages/user-setting/setting-model/hooks.ts index 1efb79fdce6..b509ed863fb 100644 --- a/web/src/pages/user-setting/setting-model/hooks.ts +++ b/web/src/pages/user-setting/setting-model/hooks.ts @@ -13,6 +13,7 @@ import { import { useFetchTenantInfo } from '@/hooks/user-setting-hooks'; import { IAddLlmRequestBody } from '@/interfaces/request/llm'; import { getRealModelName } from '@/utils/llm-util'; +import { useQueryClient } from '@tanstack/react-query'; import { useCallback, useState } from 'react'; import { ApiKeyPostBody } from '../interface'; @@ -29,7 +30,7 @@ export const useSubmitApiKey = () => { hideModal: hideApiKeyModal, showModal: showApiKeyModal, } = useSetModalState(); - + const queryClient = useQueryClient(); const onApiKeySavingOk = useCallback( async (postBody: ApiKeyPostBody) => { const ret = await saveApiKey({ @@ -38,11 +39,12 @@ export const useSubmitApiKey = () => { }); if (ret === 0) { + queryClient.invalidateQueries({ queryKey: ['llmList'] }); hideApiKeyModal(); setEditMode(false); } }, - [hideApiKeyModal, saveApiKey, savingParams], + [hideApiKeyModal, saveApiKey, savingParams, queryClient], ); const onShowApiKeyModal = useCallback( diff --git a/web/src/pages/user-setting/setting-model/index.tsx b/web/src/pages/user-setting/setting-model/index.tsx index 307a2dce1ae..af398e33c5e 100644 --- a/web/src/pages/user-setting/setting-model/index.tsx +++ b/web/src/pages/user-setting/setting-model/index.tsx @@ -193,9 +193,9 @@ const ModelProviders = () => { [showApiKeyModal, showLlmAddingModal, ModalMap, detailedLlmList], ); return ( -
+
-
+
!open && hideModal()} onOk={handleOk} @@ -77,6 +77,7 @@ const ApiKeyModal = ({ confirmLoading={loading} okText={t('save')} cancelText={t('cancel')} + className="!w-[600px]" >
@@ -85,9 +86,11 @@ const ApiKeyModal = ({ rules={{ required: t('apiKeyMessage') }} render={({ field }) => ( - + {t('apiKey')} - * Date: Tue, 11 Nov 2025 19:56:32 +0800 Subject: [PATCH 3/8] =?UTF-8?q?fix=EF=BC=9AGoogle-drive=20modal=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data-source/component/google-drive-token-field.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/pages/user-setting/data-source/component/google-drive-token-field.tsx b/web/src/pages/user-setting/data-source/component/google-drive-token-field.tsx index 1f0d91617fe..50a055f52f6 100644 --- a/web/src/pages/user-setting/data-source/component/google-drive-token-field.tsx +++ b/web/src/pages/user-setting/data-source/component/google-drive-token-field.tsx @@ -302,7 +302,7 @@ const GoogleDriveTokenField = ({
)} Date: Wed, 12 Nov 2025 11:55:03 +0800 Subject: [PATCH 4/8] Fixes: Fixed some bugs - Removed login page animation - Modified some styles in the user profile center --- web/src/locales/en.ts | 11 ++++++----- web/src/locales/zh.ts | 1 + web/src/pages/login-next/bg.tsx | 18 ++++++++++++++---- web/src/pages/login-next/index.less | 9 +++++---- web/src/pages/login-next/index.tsx | 9 +++++---- .../pages/user-setting/data-source/contant.tsx | 2 +- .../components/system-setting.tsx | 2 +- .../setting-model/components/un-add-model.tsx | 6 ++---- 8 files changed, 35 insertions(+), 23 deletions(-) diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index b84c25490d8..66bd46b2c28 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -694,6 +694,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s tocEnhanceTip: ` During the parsing of the document, table of contents information was generated (see the 'Enable Table of Contents Extraction' option in the General method). This allows the large model to return table of contents items relevant to the user's query, thereby using these items to retrieve related chunks and apply weighting to these chunks during the sorting process. This approach is derived from mimicking the behavioral logic of how humans search for knowledge in books.`, }, setting: { + selectModelPlaceholder: 'Select model', configureModelTitle: 'Configure model', confluenceIsCloudTip: 'Check if this is a Confluence Cloud instance, uncheck for Confluence Server/Data Center', @@ -729,7 +730,7 @@ Example: general/v2/`, google_driveSharedFoldersTip: 'Comma-separated Google Drive folder links to crawl.', availableSourcesDescription: 'Select a data source to add', - availableSources: 'Available Sources', + availableSources: 'Available sources', datasourceDescription: 'Manage your data source and connections', save: 'Save', search: 'Search', @@ -748,7 +749,7 @@ Example: general/v2/`, 'Please enter your current password to change your password.', model: 'Model providers', systemModelDescription: 'Please complete these settings before beginning', - dataSources: 'Data Sources', + dataSources: 'Data sources', team: 'Team', system: 'System', logout: 'Log out', @@ -924,8 +925,8 @@ Example: general/v2/`, invite: 'Invite Member', agree: 'Accept', refuse: 'Decline', - teamMembers: 'Team Members', - joinedTeams: 'Joined Teams', + teamMembers: 'Team members', + joinedTeams: 'Joined teams', sureDelete: 'Are you sure to remove this member?', quit: 'Quit', sureQuit: 'Are you sure you want to quit the team you joined?', @@ -1825,7 +1826,7 @@ Important structured information may include: names, dates, locations, events, k addMCP: 'Add MCP', editMCP: 'Edit MCP', toolsAvailable: 'tools available', - mcpServers: 'MCP Servers', + mcpServers: 'MCP servers', customizeTheListOfMcpServers: 'Customize the list of MCP servers', cachedTools: 'cached tools', bulkManage: 'Bulk manage', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 9c90d734bdf..4e6f7e0d9db 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -684,6 +684,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`, }, setting: { + selectModelPlaceholder: '请选择模型', configureModelTitle: '配置模型', confluenceIsCloudTip: '检查这是否是 Confluence Cloud 实例,如果是 Confluence 服务/数据中心,则取消选中。', diff --git a/web/src/pages/login-next/bg.tsx b/web/src/pages/login-next/bg.tsx index a4ec0885322..776db19c025 100644 --- a/web/src/pages/login-next/bg.tsx +++ b/web/src/pages/login-next/bg.tsx @@ -5,7 +5,9 @@ const aspectRatio = { bottom: 704, }; -export const BgSvg = () => { +export const BgSvg = ({ isPaused = false }: { isPaused?: boolean }) => { + const animationClass = isPaused ? 'paused' : ''; + const def = ( path: string, id: number | string = '', @@ -122,9 +124,17 @@ export const BgSvg = () => { }; return (
+
{def( @@ -134,7 +144,7 @@ export const BgSvg = () => { )}
{def( @@ -144,7 +154,7 @@ export const BgSvg = () => { )}
{def( diff --git a/web/src/pages/login-next/index.less b/web/src/pages/login-next/index.less index 7c52f360ab7..f226b9280f2 100644 --- a/web/src/pages/login-next/index.less +++ b/web/src/pages/login-next/index.less @@ -1,6 +1,3 @@ -.animate-glow { - animation: glow 16s infinite linear; -} .mask-path { stroke-width: 8; ::after { @@ -34,7 +31,9 @@ stroke-dashoffset: -600; } /* 15+300-30=285 */ } - +.animate-glow { + animation: glow 16s infinite linear; +} .animate-highlight { animation: highlight-flow 16s linear infinite; } @@ -47,11 +46,13 @@ min-height: 680px; display: flex; align-items: center; + will-change: transform; } .transform-style-3d { transform-style: preserve-3d; -webkit-transform-style: preserve-3d; transition-duration: 0.4s; + will-change: transform; } .backface-hidden { backface-visibility: hidden; diff --git a/web/src/pages/login-next/index.tsx b/web/src/pages/login-next/index.tsx index c9354225f80..1db5e7fbf43 100644 --- a/web/src/pages/login-next/index.tsx +++ b/web/src/pages/login-next/index.tsx @@ -42,7 +42,9 @@ const Login = () => { useLoginWithChannel(); const { t } = useTranslation('translation', { keyPrefix: 'login' }); const [isLoginPage, setIsLoginPage] = useState(true); - const [showPassword, setShowPassword] = useState(false); + + const [isUserInteracting, setIsUserInteracting] = useState(true); + const loading = signLoading || registerLoading || @@ -152,9 +154,8 @@ const Login = () => { color={'rgb(128, 255, 248)'} />
- + - {/* */}
@@ -237,7 +238,7 @@ const Login = () => {
( + render: (fieldProps: any) => ( { value={value} options={options} onChange={(value) => handleFieldChange(id, value)} - placeholder={tcommon('selectPlaceholder')} + placeholder={t('selectModelPlaceholder')} />
); diff --git a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx index 3d8b1d5e274..88897ce831a 100644 --- a/web/src/pages/user-setting/setting-model/components/un-add-model.tsx +++ b/web/src/pages/user-setting/setting-model/components/un-add-model.tsx @@ -123,16 +123,14 @@ export const AvailableModels: FC<{
handleAddModel(model.name)} >

{model.name}

- From 79de01ae8d0b487cc5f9fcf3fcaf572030ce2beb Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Wed, 12 Nov 2025 12:03:39 +0800 Subject: [PATCH 5/8] fix: css position --- web/src/pages/login-next/bg.tsx | 8 -------- web/src/pages/login-next/index.less | 7 +++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/web/src/pages/login-next/bg.tsx b/web/src/pages/login-next/bg.tsx index 776db19c025..2ac801e4a3e 100644 --- a/web/src/pages/login-next/bg.tsx +++ b/web/src/pages/login-next/bg.tsx @@ -124,14 +124,6 @@ export const BgSvg = ({ isPaused = false }: { isPaused?: boolean }) => { }; return (
-
Date: Wed, 12 Nov 2025 14:07:29 +0800 Subject: [PATCH 6/8] fix: Bug Fixes - Fixed the menu order in the user center - Added a disabled RAPTOR scope - Fixed some style issues --- web/src/components/originui/select-with-search.tsx | 4 ++-- .../components/parse-configuration/raptor-form-fields.tsx | 2 +- web/src/locales/en.ts | 8 ++++---- web/src/pages/user-setting/sidebar/index.tsx | 8 ++++---- web/src/routes.ts | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/web/src/components/originui/select-with-search.tsx b/web/src/components/originui/select-with-search.tsx index 4a1e1e74e3a..595844f4991 100644 --- a/web/src/components/originui/select-with-search.tsx +++ b/web/src/components/originui/select-with-search.tsx @@ -149,13 +149,13 @@ export const SelectWithSearch = forwardRef< {selectLabel} ) : ( - {placeholder} + {placeholder} )}
{value && allowClear && ( <>
- +
{t('scopeDataset')} {t('scopeSingleFile')} diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 913330d50c6..e176b7e3db4 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -788,8 +788,8 @@ Example: general/v2/`, 'Please enter the API key (for locally deployed model,ignore this).', apiKeyTip: 'The API key can be obtained by registering the corresponding LLM supplier.', - showMoreModels: 'View Models', - hideModels: 'Hide Models', + showMoreModels: 'View models', + hideModels: 'Hide models', baseUrl: 'Base-Url', baseUrlTip: 'If your API key is from OpenAI, just ignore it. Any other intermediate providers will give this base url with the API key.', @@ -814,7 +814,7 @@ Example: general/v2/`, ttsModel: 'TTS', ttsModelTip: 'The default text-to-speech model. If you cannot find a model from the dropdown, check https://ragflow.io/docs/dev/supported_models to see if your model provider supports this model.', - workspace: 'Workspace', + workspace: 'workspace', upgrade: 'Upgrade', addLlmTitle: 'Add LLM', editLlmTitle: 'Edit {{name}} Model', @@ -922,7 +922,7 @@ Example: general/v2/`, add: 'Add', updateDate: 'Date', role: 'State', - invite: 'Invite Member', + invite: 'Invite member', agree: 'Accept', refuse: 'Decline', teamMembers: 'Team members', diff --git a/web/src/pages/user-setting/sidebar/index.tsx b/web/src/pages/user-setting/sidebar/index.tsx index 20f20fdde42..16595803586 100644 --- a/web/src/pages/user-setting/sidebar/index.tsx +++ b/web/src/pages/user-setting/sidebar/index.tsx @@ -17,9 +17,11 @@ import { useEffect } from 'react'; import { useHandleMenuClick } from './hooks'; const menuItems = [ - { icon: User, label: t('setting.profile'), key: Routes.Profile }, - { icon: Users, label: t('setting.team'), key: Routes.Team }, + { icon: Server, label: t('setting.dataSources'), key: Routes.DataSource }, { icon: Box, label: t('setting.model'), key: Routes.Model }, + { icon: Banknote, label: 'MCP', key: Routes.Mcp }, + { icon: Users, label: t('setting.team'), key: Routes.Team }, + { icon: User, label: t('setting.profile'), key: Routes.Profile }, { icon: Unplug, label: t('setting.api'), key: Routes.Api }, // { // icon: MessageSquareQuote, @@ -27,10 +29,8 @@ const menuItems = [ // key: Routes.Profile, // }, // { icon: TextSearch, label: 'Retrieval Templates', key: Routes.Profile }, - { icon: Server, label: t('setting.dataSources'), key: Routes.DataSource }, // { icon: Cog, label: t('setting.system'), key: Routes.System }, // { icon: Banknote, label: 'Plan', key: Routes.Plan }, - { icon: Banknote, label: 'MCP', key: Routes.Mcp }, ]; export function SideBar() { diff --git a/web/src/routes.ts b/web/src/routes.ts index 2e9692120fe..56dd840775c 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -367,7 +367,7 @@ const routes = [ component: '@/pages/user-setting', layout: false, routes: [ - { path: '/user-setting', redirect: '/user-setting/profile' }, + { path: '/user-setting', redirect: `/user-setting${Routes.DataSource}` }, { path: '/user-setting/profile', // component: '@/pages/user-setting/setting-profile', From 3fecb784c9492a430876c11cbb9456a5bb93c26f Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Wed, 12 Nov 2025 14:17:23 +0800 Subject: [PATCH 7/8] Fix: Disabled admin-login page animation --- web/src/pages/admin/login.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/pages/admin/login.tsx b/web/src/pages/admin/login.tsx index 589db8a88ca..33f696052d1 100644 --- a/web/src/pages/admin/login.tsx +++ b/web/src/pages/admin/login.tsx @@ -126,7 +126,7 @@ function AdminLogin() { color="rgb(128, 255, 248)" /> - +
From c2a6710784606af6eaac64e79c62f4eb0bfd9111 Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Wed, 12 Nov 2025 16:49:22 +0800 Subject: [PATCH 8/8] Fix: Profile picture cropping supported --- web/src/components/avatar-upload.tsx | 287 ++++++++++++++++++++++++++- web/src/locales/en.ts | 3 + web/src/locales/zh.ts | 2 + web/src/utils/file-util.ts | 7 +- 4 files changed, 292 insertions(+), 7 deletions(-) diff --git a/web/src/components/avatar-upload.tsx b/web/src/components/avatar-upload.tsx index 7a85e08defb..9f4a3707662 100644 --- a/web/src/components/avatar-upload.tsx +++ b/web/src/components/avatar-upload.tsx @@ -5,12 +5,14 @@ import { forwardRef, useCallback, useEffect, + useRef, useState, } from 'react'; import { useTranslation } from 'react-i18next'; import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; import { Button } from './ui/button'; import { Input } from './ui/input'; +import { Modal } from './ui/modal/modal'; type AvatarUploadProps = { value?: string; @@ -22,14 +24,24 @@ export const AvatarUpload = forwardRef( function AvatarUpload({ value, onChange, tips }, ref) { const { t } = useTranslation(); const [avatarBase64Str, setAvatarBase64Str] = useState(''); // Avatar Image base64 + const [isCropModalOpen, setIsCropModalOpen] = useState(false); + const [imageToCrop, setImageToCrop] = useState(null); + const [cropArea, setCropArea] = useState({ x: 0, y: 0, size: 200 }); + const imageRef = useRef(null); + const canvasRef = useRef(null); + const containerRef = useRef(null); + const isDraggingRef = useRef(false); + const dragStartRef = useRef({ x: 0, y: 0 }); + const [imageScale, setImageScale] = useState(1); + const [imageOffset, setImageOffset] = useState({ x: 0, y: 0 }); const handleChange: ChangeEventHandler = useCallback( async (ev) => { const file = ev.target?.files?.[0]; if (/\.(jpg|jpeg|png|webp|bmp)$/i.test(file?.name ?? '')) { - const str = await transformFile2Base64(file!); - setAvatarBase64Str(str); - onChange?.(str); + const str = await transformFile2Base64(file!, 1000); + setImageToCrop(str); + setIsCropModalOpen(true); } ev.target.value = ''; }, @@ -41,17 +53,209 @@ export const AvatarUpload = forwardRef( onChange?.(''); }, [onChange]); + const handleCrop = useCallback(() => { + if (!imageRef.current || !canvasRef.current) return; + + const canvas = canvasRef.current; + const ctx = canvas.getContext('2d'); + const image = imageRef.current; + + if (!ctx) return; + + // Set canvas size to 64x64 (avatar size) + canvas.width = 64; + canvas.height = 64; + + // Draw cropped image on canvas + ctx.drawImage( + image, + cropArea.x, + cropArea.y, + cropArea.size, + cropArea.size, + 0, + 0, + 64, + 64, + ); + + // Convert to base64 + const croppedImageBase64 = canvas.toDataURL('image/png'); + setAvatarBase64Str(croppedImageBase64); + onChange?.(croppedImageBase64); + setIsCropModalOpen(false); + }, [cropArea, onChange]); + + const handleCancelCrop = useCallback(() => { + setIsCropModalOpen(false); + setImageToCrop(null); + }, []); + + const initCropArea = useCallback(() => { + if (!imageRef.current || !containerRef.current) return; + + const image = imageRef.current; + const container = containerRef.current; + + // Calculate image scale to fit container + const scale = Math.min( + container.clientWidth / image.width, + container.clientHeight / image.height, + ); + setImageScale(scale); + + // Calculate image offset to center it + const scaledWidth = image.width * scale; + const scaledHeight = image.height * scale; + const offsetX = (container.clientWidth - scaledWidth) / 2; + const offsetY = (container.clientHeight - scaledHeight) / 2; + setImageOffset({ x: offsetX, y: offsetY }); + + // Initialize crop area to center of image + const size = Math.min(scaledWidth, scaledHeight) * 0.8; // 80% of the smaller dimension + const x = (image.width - size / scale) / 2; + const y = (image.height - size / scale) / 2; + + setCropArea({ x, y, size: size / scale }); + }, []); + + const handleMouseMove = useCallback( + (e: MouseEvent) => { + if ( + !isDraggingRef.current || + !imageRef.current || + !containerRef.current + ) + return; + + const image = imageRef.current; + const container = containerRef.current; + const containerRect = container.getBoundingClientRect(); + + // Calculate mouse position relative to container + const mouseX = e.clientX - containerRect.left; + const mouseY = e.clientY - containerRect.top; + + // Calculate mouse position relative to image + const imageX = (mouseX - imageOffset.x) / imageScale; + const imageY = (mouseY - imageOffset.y) / imageScale; + + // Calculate new crop area position based on mouse movement + let newX = imageX - dragStartRef.current.x; + let newY = imageY - dragStartRef.current.y; + + // Boundary checks + newX = Math.max(0, Math.min(newX, image.width - cropArea.size)); + newY = Math.max(0, Math.min(newY, image.height - cropArea.size)); + + setCropArea((prev) => ({ + ...prev, + x: newX, + y: newY, + })); + }, + [cropArea.size, imageScale, imageOffset], + ); + + const handleMouseUp = useCallback(() => { + isDraggingRef.current = false; + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }, [handleMouseMove]); + + const handleMouseDown = useCallback( + (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + isDraggingRef.current = true; + if (imageRef.current && containerRef.current) { + const container = containerRef.current; + const containerRect = container.getBoundingClientRect(); + + // Calculate mouse position relative to container + const mouseX = e.clientX - containerRect.left; + const mouseY = e.clientY - containerRect.top; + + // Calculate mouse position relative to image + const imageX = (mouseX - imageOffset.x) / imageScale; + const imageY = (mouseY - imageOffset.y) / imageScale; + + // Store the offset between mouse position and crop area position + dragStartRef.current = { + x: imageX - cropArea.x, + y: imageY - cropArea.y, + }; + } + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + }, + [cropArea, imageScale, imageOffset], + ); + + const handleWheel = useCallback((e: React.WheelEvent) => { + if (!imageRef.current) return; + + e.preventDefault(); + const image = imageRef.current; + const delta = e.deltaY > 0 ? 0.9 : 1.1; // Zoom factor + + setCropArea((prev) => { + const newSize = Math.max( + 20, + Math.min(prev.size * delta, Math.min(image.width, image.height)), + ); + + // Adjust position to keep crop area centered + const centerRatioX = (prev.x + prev.size / 2) / image.width; + const centerRatioY = (prev.y + prev.size / 2) / image.height; + + const newX = centerRatioX * image.width - newSize / 2; + const newY = centerRatioY * image.height - newSize / 2; + + // Boundary checks + const boundedX = Math.max(0, Math.min(newX, image.width - newSize)); + const boundedY = Math.max(0, Math.min(newY, image.height - newSize)); + + return { + x: boundedX, + y: boundedY, + size: newSize, + }; + }); + }, []); + useEffect(() => { if (value) { setAvatarBase64Str(value); } }, [value]); + useEffect(() => { + const container = containerRef.current; + setTimeout(() => { + console.log('container', container); + // initCropArea(); + if (imageToCrop && container && isCropModalOpen) { + container.addEventListener( + 'wheel', + handleWheel as unknown as EventListener, + { passive: false }, + ); + return () => { + container.removeEventListener( + 'wheel', + handleWheel as unknown as EventListener, + ); + }; + } + }, 100); + }, [handleWheel, containerRef.current]); + return (
{!avatarBase64Str ? ( -
+

{t('common.upload')}

@@ -60,7 +264,7 @@ export const AvatarUpload = forwardRef( ) : (
- +
@@ -93,6 +297,79 @@ export const AvatarUpload = forwardRef(
{tips ?? t('knowledgeConfiguration.photoTip')}
+ + {/* Crop Modal */} + { + setIsCropModalOpen(open); + if (!open) { + setImageToCrop(null); + } + }} + title={t('setting.cropImage')} + size="small" + onCancel={handleCancelCrop} + onOk={handleCrop} + // footer={ + //
+ // + // + //
+ // } + > +
+ {imageToCrop && ( +
+
+ To crop + {imageRef.current && ( +
+ )} +
+
+

+ {t('setting.cropTip')} +

+
+ +
+ )} +
+
); }, diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index e176b7e3db4..915508692c4 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -694,6 +694,9 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s tocEnhanceTip: ` During the parsing of the document, table of contents information was generated (see the 'Enable Table of Contents Extraction' option in the General method). This allows the large model to return table of contents items relevant to the user's query, thereby using these items to retrieve related chunks and apply weighting to these chunks during the sorting process. This approach is derived from mimicking the behavioral logic of how humans search for knowledge in books.`, }, setting: { + cropTip: + 'Drag the selection area to choose the cropping position of the image, and scroll to zoom in/out', + cropImage: 'Crop image', selectModelPlaceholder: 'Select model', configureModelTitle: 'Configure model', confluenceIsCloudTip: diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 4e6f7e0d9db..a5f4a9d525a 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -684,6 +684,8 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`, }, setting: { + cropTip: '拖动选区可以选择要图片的裁剪位置,滚动可以放大/缩小选区', + cropImage: '剪裁图片', selectModelPlaceholder: '请选择模型', configureModelTitle: '配置模型', confluenceIsCloudTip: diff --git a/web/src/utils/file-util.ts b/web/src/utils/file-util.ts index 6d8ef9a4371..a9d2968c087 100644 --- a/web/src/utils/file-util.ts +++ b/web/src/utils/file-util.ts @@ -2,7 +2,10 @@ import { FileMimeType } from '@/constants/common'; import fileManagerService from '@/services/file-manager-service'; import { UploadFile } from 'antd'; -export const transformFile2Base64 = (val: any): Promise => { +export const transformFile2Base64 = ( + val: any, + imgSize?: number, +): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(val); @@ -19,7 +22,7 @@ export const transformFile2Base64 = (val: any): Promise => { // Calculate compressed dimensions, set max width/height to 800px let width = img.width; let height = img.height; - const maxSize = 100; + const maxSize = imgSize ?? 100; if (width > height && width > maxSize) { height = (height * maxSize) / width;